chrome-devtools-frontend 1.0.1622369 → 1.0.1624583

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 (101) hide show
  1. package/.agents/skills/foundation-test-migration/SKILL.md +1 -1
  2. package/front_end/Images/src/expand.svg +1 -0
  3. package/front_end/core/host/AidaClient.ts +6 -5
  4. package/front_end/core/host/AidaClientTypes.ts +3 -1
  5. package/front_end/core/host/DispatchHttpRequestClient.ts +6 -3
  6. package/front_end/core/platform/api/HostRuntime.ts +3 -0
  7. package/front_end/core/platform/browser/HostRuntime.ts +10 -0
  8. package/front_end/core/platform/node/HostRuntime.ts +10 -0
  9. package/front_end/core/root/Runtime.ts +6 -5
  10. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +72 -8
  11. package/front_end/entrypoints/greendev_floaty/floaty.html +1 -1
  12. package/front_end/generated/Deprecation.ts +7 -0
  13. package/front_end/generated/InspectorBackendCommands.ts +1 -1
  14. package/front_end/generated/SupportedCSSProperties.js +6 -6
  15. package/front_end/generated/protocol.ts +1 -0
  16. package/front_end/models/ai_assistance/agents/GreenDevAgent.ts +373 -112
  17. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +57 -0
  18. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +2 -1
  19. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +3 -10
  20. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +2 -3
  21. package/front_end/models/ai_code_generation/AiCodeGeneration.ts +2 -3
  22. package/front_end/models/javascript_metadata/NativeFunctions.js +9 -4
  23. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +8 -4
  24. package/front_end/panels/ai_assistance/components/ChatMessage.ts +219 -8
  25. package/front_end/panels/ai_assistance/components/ChatView.ts +2 -2
  26. package/front_end/panels/console/ConsoleView.ts +86 -7
  27. package/front_end/panels/console/ConsoleViewMessage.ts +23 -1
  28. package/front_end/panels/elements/StylePropertiesSection.ts +1 -2
  29. package/front_end/panels/elements/StylePropertyTreeElement.ts +3 -3
  30. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +11 -2
  31. package/front_end/panels/elements/StylesSidebarPane.ts +29 -5
  32. package/front_end/panels/elements/stylePropertiesTreeOutline.css +5 -1
  33. package/front_end/panels/emulation/DeviceModeToolbar.ts +37 -13
  34. package/front_end/panels/emulation/deviceModeView.css +25 -0
  35. package/front_end/panels/greendev/GreenDevPanel.ts +30 -3
  36. package/front_end/panels/media/EventDisplayTable.ts +1 -1
  37. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +48 -27
  38. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +67 -38
  39. package/front_end/panels/network/NetworkConfigView.ts +1 -1
  40. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -22
  41. package/front_end/third_party/chromium/README.chromium +1 -1
  42. package/front_end/third_party/lighthouse/README.chromium +2 -2
  43. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +5176 -5104
  44. package/front_end/third_party/lighthouse/locales/ar-XB.json +72 -36
  45. package/front_end/third_party/lighthouse/locales/ar.json +72 -36
  46. package/front_end/third_party/lighthouse/locales/bg.json +72 -36
  47. package/front_end/third_party/lighthouse/locales/ca.json +72 -36
  48. package/front_end/third_party/lighthouse/locales/cs.json +72 -36
  49. package/front_end/third_party/lighthouse/locales/da.json +74 -38
  50. package/front_end/third_party/lighthouse/locales/de.json +72 -36
  51. package/front_end/third_party/lighthouse/locales/el.json +73 -37
  52. package/front_end/third_party/lighthouse/locales/en-GB.json +74 -38
  53. package/front_end/third_party/lighthouse/locales/en-US.json +245 -17
  54. package/front_end/third_party/lighthouse/locales/en-XL.json +245 -17
  55. package/front_end/third_party/lighthouse/locales/es-419.json +72 -36
  56. package/front_end/third_party/lighthouse/locales/es.json +73 -37
  57. package/front_end/third_party/lighthouse/locales/fi.json +72 -36
  58. package/front_end/third_party/lighthouse/locales/fil.json +74 -38
  59. package/front_end/third_party/lighthouse/locales/fr.json +162 -126
  60. package/front_end/third_party/lighthouse/locales/he.json +74 -38
  61. package/front_end/third_party/lighthouse/locales/hi.json +73 -37
  62. package/front_end/third_party/lighthouse/locales/hr.json +72 -36
  63. package/front_end/third_party/lighthouse/locales/hu.json +73 -37
  64. package/front_end/third_party/lighthouse/locales/id.json +74 -38
  65. package/front_end/third_party/lighthouse/locales/it.json +72 -36
  66. package/front_end/third_party/lighthouse/locales/ja.json +72 -36
  67. package/front_end/third_party/lighthouse/locales/ko.json +72 -36
  68. package/front_end/third_party/lighthouse/locales/lt.json +72 -36
  69. package/front_end/third_party/lighthouse/locales/lv.json +72 -36
  70. package/front_end/third_party/lighthouse/locales/nl.json +73 -37
  71. package/front_end/third_party/lighthouse/locales/no.json +72 -36
  72. package/front_end/third_party/lighthouse/locales/pl.json +72 -36
  73. package/front_end/third_party/lighthouse/locales/pt-PT.json +72 -36
  74. package/front_end/third_party/lighthouse/locales/pt.json +74 -38
  75. package/front_end/third_party/lighthouse/locales/ro.json +72 -36
  76. package/front_end/third_party/lighthouse/locales/ru.json +72 -36
  77. package/front_end/third_party/lighthouse/locales/sk.json +72 -36
  78. package/front_end/third_party/lighthouse/locales/sl.json +72 -36
  79. package/front_end/third_party/lighthouse/locales/sr-Latn.json +73 -37
  80. package/front_end/third_party/lighthouse/locales/sr.json +73 -37
  81. package/front_end/third_party/lighthouse/locales/sv.json +75 -39
  82. package/front_end/third_party/lighthouse/locales/ta.json +73 -37
  83. package/front_end/third_party/lighthouse/locales/te.json +72 -36
  84. package/front_end/third_party/lighthouse/locales/th.json +73 -37
  85. package/front_end/third_party/lighthouse/locales/tr.json +72 -36
  86. package/front_end/third_party/lighthouse/locales/uk.json +72 -36
  87. package/front_end/third_party/lighthouse/locales/vi.json +74 -38
  88. package/front_end/third_party/lighthouse/locales/zh-HK.json +72 -36
  89. package/front_end/third_party/lighthouse/locales/zh-TW.json +74 -38
  90. package/front_end/third_party/lighthouse/locales/zh.json +75 -39
  91. package/front_end/third_party/lighthouse/report/bundle.js +2 -1
  92. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  93. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +6 -2
  94. package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +4 -1
  95. package/front_end/ui/legacy/SuggestBox.ts +1 -0
  96. package/front_end/ui/legacy/TextPrompt.ts +2 -1
  97. package/front_end/ui/legacy/UIUtils.ts +26 -4
  98. package/front_end/ui/visual_logging/KnownContextValues.ts +20 -0
  99. package/package.json +9 -8
  100. package/front_end/panels/emulation/components/DeviceSizeInputElement.ts +0 -134
  101. package/front_end/panels/emulation/components/components.ts +0 -9
@@ -14,7 +14,6 @@ import {debugLog} from './debug.js';
14
14
  interface AgentOptions {
15
15
  aidaClient: Host.AidaClient.AidaClient;
16
16
  serverSideLoggingEnabled?: boolean;
17
- confirmSideEffectForTest?: typeof Promise.withResolvers;
18
17
  }
19
18
 
20
19
  interface RequestOptions {
@@ -274,7 +273,7 @@ export class AiCodeCompletion {
274
273
 
275
274
  void this.#aidaClient.registerClientEvent({
276
275
  corresponding_aida_rpc_global_id: rpcGlobalId,
277
- disable_user_content_logging: true,
276
+ disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
278
277
  complete_code_client_event: {
279
278
  user_impression: {
280
279
  sample: {
@@ -296,7 +295,7 @@ export class AiCodeCompletion {
296
295
  registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
297
296
  void this.#aidaClient.registerClientEvent({
298
297
  corresponding_aida_rpc_global_id: rpcGlobalId,
299
- disable_user_content_logging: true,
298
+ disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
300
299
  complete_code_client_event: {
301
300
  user_acceptance: {
302
301
  sample: {
@@ -39,7 +39,6 @@ The console has direct access to the inspected page's \`window\` and \`document\
39
39
  interface Options {
40
40
  aidaClient: Host.AidaClient.AidaClient;
41
41
  serverSideLoggingEnabled?: boolean;
42
- confirmSideEffectForTest?: typeof Promise.withResolvers;
43
42
  }
44
43
 
45
44
  interface RequestOptions {
@@ -124,7 +123,7 @@ export class AiCodeGeneration {
124
123
 
125
124
  void this.#aidaClient.registerClientEvent({
126
125
  corresponding_aida_rpc_global_id: rpcGlobalId,
127
- disable_user_content_logging: true,
126
+ disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
128
127
  generate_code_client_event: {
129
128
  user_impression: {
130
129
  sample: {
@@ -146,7 +145,7 @@ export class AiCodeGeneration {
146
145
  registerUserAcceptance(rpcGlobalId: Host.AidaClient.RpcGlobalId, sampleId?: number): void {
147
146
  void this.#aidaClient.registerClientEvent({
148
147
  corresponding_aida_rpc_global_id: rpcGlobalId,
149
- disable_user_content_logging: true,
148
+ disable_user_content_logging: !(this.#serverSideLoggingEnabled ?? false),
150
149
  generate_code_client_event: {
151
150
  user_acceptance: {
152
151
  sample: {
@@ -2324,6 +2324,11 @@ export const NativeFunctions = [
2324
2324
  signatures: [["type"]],
2325
2325
  receivers: ["HTMLScriptElement","ClipboardItem"]
2326
2326
  },
2327
+ {
2328
+ name: "supports",
2329
+ signatures: [["operation","algorithm","?length"],["operation","algorithm","additionalAlgorithm"]],
2330
+ receivers: ["SubtleCrypto"]
2331
+ },
2327
2332
  {
2328
2333
  name: "toggle",
2329
2334
  signatures: [["token","?force"]]
@@ -7435,10 +7440,6 @@ export const NativeFunctions = [
7435
7440
  name: "setReportEventDataForAutomaticBeacons",
7436
7441
  signatures: [["event"]]
7437
7442
  },
7438
- {
7439
- name: "notifyEvent",
7440
- signatures: [["triggering_event"]]
7441
- },
7442
7443
  {
7443
7444
  name: "FencedFrameConfig",
7444
7445
  signatures: [["url"]]
@@ -9391,6 +9392,10 @@ export const NativeFunctions = [
9391
9392
  name: "startDiagnosticLogging",
9392
9393
  signatures: [["?options"]]
9393
9394
  },
9395
+ {
9396
+ name: "finishDiagnosticLogging",
9397
+ signatures: [["?options"]]
9398
+ },
9394
9399
  {
9395
9400
  name: "CloseEvent",
9396
9401
  signatures: [["type","?eventInitDict"]]
@@ -531,7 +531,7 @@ function defaultView(input: ViewInput, output: PanelViewOutput, target: HTMLElem
531
531
  let walkthroughIsForLastMessage = false;
532
532
  if(input.state === ViewState.CHAT_VIEW) {
533
533
  const lastMessage = input.props.messages.at(-1);
534
- if(lastMessage && input.props.walkthrough.activeSidebarMessage === lastMessage) {
534
+ if(lastMessage && input.props.walkthrough.activeSidebarMessage?.id === lastMessage.id) {
535
535
  walkthroughIsForLastMessage = true;
536
536
  }
537
537
  }
@@ -879,7 +879,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
879
879
  }
880
880
 
881
881
  #openWalkthrough(message: ModelChatMessage): void {
882
- if (!this.#walkthrough.inlineExpandedMessages.includes(message)) {
882
+ if (!this.#walkthrough.inlineExpandedMessages.some(m => m.id === message.id)) {
883
883
  this.#walkthrough.inlineExpandedMessages.push(message);
884
884
  }
885
885
  this.#walkthrough.activeSidebarMessage = message;
@@ -905,7 +905,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
905
905
  }
906
906
 
907
907
  // If we are closing a walkthrough, remove it from the list of expanded messages.
908
- this.#walkthrough.inlineExpandedMessages = this.#walkthrough.inlineExpandedMessages.filter(m => m !== message);
908
+ this.#walkthrough.inlineExpandedMessages =
909
+ this.#walkthrough.inlineExpandedMessages.filter(m => m.id !== message.id);
909
910
 
910
911
  if (this.#walkthrough.isInlined) {
911
912
  // In Narrow mode, the global expanded state tracks if at least one walkthrough is open.
@@ -913,7 +914,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
913
914
  // If the message we just closed was the active one, we pick a new active message
914
915
  // from the remaining open ones (if any). This ensures that if the user
915
916
  // re-opens the sidebar later, it shows the most recently opened walkthrough.
916
- if (this.#walkthrough.activeSidebarMessage === message) {
917
+ if (this.#walkthrough.activeSidebarMessage?.id === message.id) {
917
918
  this.#walkthrough.activeSidebarMessage = this.#walkthrough.inlineExpandedMessages.at(-1) ?? null;
918
919
  }
919
920
  } else {
@@ -1857,6 +1858,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1857
1858
  let systemMessage: ModelChatMessage = {
1858
1859
  entity: ChatMessageEntity.MODEL,
1859
1860
  parts: [],
1861
+ id: crypto.randomUUID(),
1860
1862
  };
1861
1863
  let step: Step = {isLoading: true};
1862
1864
 
@@ -1885,10 +1887,12 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1885
1887
  entity: ChatMessageEntity.USER,
1886
1888
  text: data.query,
1887
1889
  imageInput: data.imageInput,
1890
+ id: crypto.randomUUID(),
1888
1891
  });
1889
1892
  systemMessage = {
1890
1893
  entity: ChatMessageEntity.MODEL,
1891
1894
  parts: [],
1895
+ id: crypto.randomUUID(),
1892
1896
  };
1893
1897
  this.#messages.push(systemMessage);
1894
1898
  // If the walkthrough is currently expanded in the sidebar, we want to
@@ -46,7 +46,7 @@ const {html, Directives: {ref, ifDefined}} = Lit;
46
46
  const lockedString = i18n.i18n.lockedString;
47
47
  const {widget} = UI.Widget;
48
48
 
49
- const REPORT_URL = 'https://crbug.com/364805393' as Platform.DevToolsPath.UrlString;
49
+ const REPORT_URL = 'https://crbug.com/508304827' as Platform.DevToolsPath.UrlString;
50
50
  const SCROLL_ROUNDING_OFFSET = 1;
51
51
  const MAX_NUM_LINES_IN_CODEBLOCK = 11;
52
52
 
@@ -227,6 +227,14 @@ const UIStringsNotTranslate = {
227
227
  * @description Accessible label for the reveal button in the bottom up thread activity widget.
228
228
  */
229
229
  revealBottomUpTree: 'Reveal bottom-up thread activity',
230
+ /**
231
+ * @description Accessible label for the reveal button in the network dependency tree widget.
232
+ */
233
+ revealNetworkDependencyTree: 'Reveal network dependency tree',
234
+ /**
235
+ * @description Accessible label for the reveal button in the 3rd parties widget.
236
+ */
237
+ revealThirdParties: 'Reveal 3rd parties',
230
238
  /**
231
239
  * @description Title for the core web vitals widget.
232
240
  */
@@ -247,6 +255,14 @@ const UIStringsNotTranslate = {
247
255
  * @description Title for the render-blocking requests widget.
248
256
  */
249
257
  renderBlockingBreakdown: 'Render-blocking requests',
258
+ /**
259
+ * @description Title for the network dependency tree widget.
260
+ */
261
+ networkDependencyTree: 'Network dependency tree',
262
+ /**
263
+ * @description Title for the 3rd parties widget.
264
+ */
265
+ thirdParties: '3rd parties',
250
266
  /**
251
267
  * @description Title for the LCP element widget.
252
268
  */
@@ -263,6 +279,110 @@ const UIStringsNotTranslate = {
263
279
  * @description Title for the bottom up thread activity widget.
264
280
  */
265
281
  bottomUpTree: 'Bottom-up thread activity',
282
+ /**
283
+ * @description Accessible label for the reveal button in the forced reflow widget.
284
+ */
285
+ revealForcedReflow: 'Reveal forced reflow',
286
+ /**
287
+ * @description Title for the forced reflow widget.
288
+ */
289
+ forcedReflow: 'Forced reflow',
290
+ /**
291
+ * @description Accessible label for the reveal button in the cache widget.
292
+ */
293
+ revealCache: 'Reveal efficient cache lifetimes',
294
+ /**
295
+ * @description Title for the cache widget.
296
+ */
297
+ cache: 'Efficient cache lifetimes',
298
+ /**
299
+ * @description Accessible label for the reveal button in the INP breakdown widget.
300
+ */
301
+ revealInpBreakdown: 'Reveal INP breakdown',
302
+ /**
303
+ * @description Title for the INP breakdown widget.
304
+ */
305
+ inpBreakdown: 'INP breakdown',
306
+ /**
307
+ * @description Accessible label for the reveal button in the document latency widget.
308
+ */
309
+ revealDocumentLatency: 'Reveal document latency',
310
+ /**
311
+ * @description Title for the document latency widget.
312
+ */
313
+ documentLatency: 'Document latency',
314
+ /**
315
+ * @description Accessible label for the reveal button in the DOM size widget.
316
+ */
317
+ revealDomSize: 'Reveal DOM size',
318
+ /**
319
+ * @description Title for the DOM size widget.
320
+ */
321
+ domSize: 'DOM size',
322
+ /**
323
+ * @description Accessible label for the reveal button in the duplicated JavaScript widget.
324
+ */
325
+ revealDuplicateJavaScript: 'Reveal duplicated JavaScript',
326
+ /**
327
+ * @description Title for the duplicated JavaScript widget.
328
+ */
329
+ duplicateJavaScript: 'Duplicated JavaScript',
330
+ /**
331
+ * @description Accessible label for the reveal button in the image delivery widget.
332
+ */
333
+ revealImageDelivery: 'Reveal image delivery',
334
+ /**
335
+ * @description Title for the image delivery widget.
336
+ */
337
+ imageDelivery: 'Image delivery',
338
+ /**
339
+ * @description Accessible label for the reveal button in the font display widget.
340
+ */
341
+ revealFontDisplay: 'Reveal font display',
342
+ /**
343
+ * @description Title for the font display widget.
344
+ */
345
+ fontDisplay: 'Font display',
346
+ /**
347
+ * @description Accessible label for the reveal button in the slow CSS selectors widget.
348
+ */
349
+ revealSlowCssSelector: 'Reveal slow CSS selectors',
350
+ /**
351
+ * @description Title for the slow CSS selectors widget.
352
+ */
353
+ slowCssSelector: 'Slow CSS selectors',
354
+ /**
355
+ * @description Accessible label for the reveal button in the legacy JavaScript widget.
356
+ */
357
+ revealLegacyJavaScript: 'Reveal legacy JavaScript',
358
+ /**
359
+ * @description Title for the legacy JavaScript widget.
360
+ */
361
+ legacyJavaScript: 'Legacy JavaScript',
362
+ /**
363
+ * @description Accessible label for the reveal button in the viewport optimization widget.
364
+ */
365
+ revealViewport: 'Reveal viewport optimization',
366
+ /**
367
+ * @description Title for the viewport optimization widget.
368
+ */
369
+ viewport: 'Viewport optimization',
370
+ /**
371
+ * @description Accessible label for the reveal button in the modern HTTP usage widget.
372
+ */
373
+ revealModernHttp: 'Reveal modern HTTP usage',
374
+ /**
375
+ * @description Title for the modern HTTP usage widget.
376
+ */
377
+ modernHttp: 'Modern HTTP usage',
378
+ /**
379
+ * @description Accessible label for the reveal button in the character set declaration widget.
380
+ */
381
+ revealCharacterSet: 'Reveal character set declaration',
382
+ /**
383
+ * @description Title for the character set declaration widget.
384
+ */
385
+ characterSet: 'Character set declaration',
266
386
  } as const;
267
387
 
268
388
  export interface Step {
@@ -315,6 +435,7 @@ export interface UserChatMessage {
315
435
  entity: ChatMessageEntity.USER;
316
436
  text: string;
317
437
  imageInput?: Host.AidaClient.Part;
438
+ id: string;
318
439
  }
319
440
 
320
441
  export interface ModelChatMessage {
@@ -322,6 +443,7 @@ export interface ModelChatMessage {
322
443
  parts: ModelMessagePart[];
323
444
  error?: AiAssistanceModel.AiAgent.ErrorType;
324
445
  rpcId?: Host.AidaClient.RpcGlobalId;
446
+ id: string;
325
447
  }
326
448
 
327
449
  export type Message = UserChatMessage|ModelChatMessage;
@@ -620,7 +742,7 @@ function renderWalkthroughSidebarButton(
620
742
  }
621
743
 
622
744
  const hasOneStepWithWidget = steps.some(step => step.widgets?.length);
623
- const isExpanded = walkthrough.isExpanded && input.message === input.walkthrough.activeSidebarMessage;
745
+ const isExpanded = walkthrough.isExpanded && input.message.id === input.walkthrough.activeSidebarMessage?.id;
624
746
  const title = isExpanded ? walkthroughCloseTitle({hasWidgets: hasOneStepWithWidget}) : walkthroughTitle({
625
747
  isLoading: input.isLoading,
626
748
  hasWidgets: hasOneStepWithWidget,
@@ -661,7 +783,7 @@ function renderWalkthroughSidebarButton(
661
783
  .jslogContext=${walkthrough.isExpanded ? 'ai-hide-walkthrough-sidebar' : 'ai-show-walkthrough-sidebar'}
662
784
  data-show-walkthrough
663
785
  @click=${() => {
664
- if(walkthrough.activeSidebarMessage === input.message && walkthrough.isExpanded) {
786
+ if(walkthrough.activeSidebarMessage?.id === input.message.id && walkthrough.isExpanded) {
665
787
  walkthrough.onToggle(false, message as ModelChatMessage);
666
788
  } else {
667
789
  // Can't just toggle the visibility here; we need to ensure we
@@ -696,8 +818,8 @@ function renderWalkthroughUI(input: ChatMessageViewInput, steps: Step[]): Lit.Li
696
818
  // open and it is specifically targeting this message. This is necessary
697
819
  // because the walkthrough state is shared across all messages in the chat.
698
820
  const isExpanded = input.walkthrough.isInlined ?
699
- input.walkthrough.inlineExpandedMessages.includes(input.message as ModelChatMessage) :
700
- (input.walkthrough.isExpanded && input.walkthrough.activeSidebarMessage === input.message);
821
+ input.walkthrough.inlineExpandedMessages.some(m => m.id === input.message.id) :
822
+ (input.walkthrough.isExpanded && input.walkthrough.activeSidebarMessage?.id === input.message.id);
701
823
 
702
824
  // clang-format off
703
825
  const walkthroughInline = input.walkthrough.isInlined ? html`
@@ -941,8 +1063,7 @@ async function makeStylePropertiesWidget(widgetData: StylePropertiesAiWidget): P
941
1063
  }
942
1064
 
943
1065
  const INSIGHT_METADATA: Record<string, {
944
- component: typeof TimelineInsights.LCPBreakdown.LCPBreakdown | typeof TimelineInsights.RenderBlocking.RenderBlocking |
945
- typeof TimelineInsights.LCPDiscovery.LCPDiscovery | typeof TimelineInsights.CLSCulprits.CLSCulprits,
1066
+ component: new () => BaseInsightComponent<Trace.Insights.Types.InsightModel>,
946
1067
  accessibleLabel: string,
947
1068
  title: string,
948
1069
  jslog: string,
@@ -971,6 +1092,96 @@ const INSIGHT_METADATA: Record<string, {
971
1092
  title: UIStringsNotTranslate.clsCulprits,
972
1093
  jslog: 'cls-culprits-widget',
973
1094
  },
1095
+ [Trace.Insights.Types.InsightKeys.NETWORK_DEPENDENCY_TREE]: {
1096
+ component: TimelineInsights.NetworkDependencyTree.NetworkDependencyTree,
1097
+ accessibleLabel: UIStringsNotTranslate.revealNetworkDependencyTree,
1098
+ title: UIStringsNotTranslate.networkDependencyTree,
1099
+ jslog: 'network-dependency-tree-widget',
1100
+ },
1101
+ [Trace.Insights.Types.InsightKeys.THIRD_PARTIES]: {
1102
+ component: TimelineInsights.ThirdParties.ThirdParties,
1103
+ accessibleLabel: UIStringsNotTranslate.revealThirdParties,
1104
+ title: UIStringsNotTranslate.thirdParties,
1105
+ jslog: 'third-parties-widget',
1106
+ },
1107
+ [Trace.Insights.Types.InsightKeys.FORCED_REFLOW]: {
1108
+ component: TimelineInsights.ForcedReflow.ForcedReflow,
1109
+ accessibleLabel: UIStringsNotTranslate.revealForcedReflow,
1110
+ title: UIStringsNotTranslate.forcedReflow,
1111
+ jslog: 'forced-reflow-widget',
1112
+ },
1113
+ [Trace.Insights.Types.InsightKeys.CACHE]: {
1114
+ component: TimelineInsights.Cache.Cache,
1115
+ accessibleLabel: UIStringsNotTranslate.revealCache,
1116
+ title: UIStringsNotTranslate.cache,
1117
+ jslog: 'cache-widget',
1118
+ },
1119
+ [Trace.Insights.Types.InsightKeys.INP_BREAKDOWN]: {
1120
+ component: TimelineInsights.INPBreakdown.INPBreakdown,
1121
+ accessibleLabel: UIStringsNotTranslate.revealInpBreakdown,
1122
+ title: UIStringsNotTranslate.inpBreakdown,
1123
+ jslog: 'inp-breakdown-widget',
1124
+ },
1125
+ [Trace.Insights.Types.InsightKeys.DOCUMENT_LATENCY]: {
1126
+ component: TimelineInsights.DocumentLatency.DocumentLatency,
1127
+ accessibleLabel: UIStringsNotTranslate.revealDocumentLatency,
1128
+ title: UIStringsNotTranslate.documentLatency,
1129
+ jslog: 'document-latency-widget',
1130
+ },
1131
+ [Trace.Insights.Types.InsightKeys.DOM_SIZE]: {
1132
+ component: TimelineInsights.DOMSize.DOMSize,
1133
+ accessibleLabel: UIStringsNotTranslate.revealDomSize,
1134
+ title: UIStringsNotTranslate.domSize,
1135
+ jslog: 'dom-size-widget',
1136
+ },
1137
+ [Trace.Insights.Types.InsightKeys.DUPLICATE_JAVASCRIPT]: {
1138
+ component: TimelineInsights.DuplicatedJavaScript.DuplicatedJavaScript,
1139
+ accessibleLabel: UIStringsNotTranslate.revealDuplicateJavaScript,
1140
+ title: UIStringsNotTranslate.duplicateJavaScript,
1141
+ jslog: 'duplicate-javascript-widget',
1142
+ },
1143
+ [Trace.Insights.Types.InsightKeys.IMAGE_DELIVERY]: {
1144
+ component: TimelineInsights.ImageDelivery.ImageDelivery,
1145
+ accessibleLabel: UIStringsNotTranslate.revealImageDelivery,
1146
+ title: UIStringsNotTranslate.imageDelivery,
1147
+ jslog: 'image-delivery-widget',
1148
+ },
1149
+ [Trace.Insights.Types.InsightKeys.FONT_DISPLAY]: {
1150
+ component: TimelineInsights.FontDisplay.FontDisplay,
1151
+ accessibleLabel: UIStringsNotTranslate.revealFontDisplay,
1152
+ title: UIStringsNotTranslate.fontDisplay,
1153
+ jslog: 'font-display-widget',
1154
+ },
1155
+ [Trace.Insights.Types.InsightKeys.SLOW_CSS_SELECTOR]: {
1156
+ component: TimelineInsights.SlowCSSSelector.SlowCSSSelector,
1157
+ accessibleLabel: UIStringsNotTranslate.revealSlowCssSelector,
1158
+ title: UIStringsNotTranslate.slowCssSelector,
1159
+ jslog: 'slow-css-selector-widget',
1160
+ },
1161
+ [Trace.Insights.Types.InsightKeys.LEGACY_JAVASCRIPT]: {
1162
+ component: TimelineInsights.LegacyJavaScript.LegacyJavaScript,
1163
+ accessibleLabel: UIStringsNotTranslate.revealLegacyJavaScript,
1164
+ title: UIStringsNotTranslate.legacyJavaScript,
1165
+ jslog: 'legacy-javascript-widget',
1166
+ },
1167
+ [Trace.Insights.Types.InsightKeys.VIEWPORT]: {
1168
+ component: TimelineInsights.Viewport.Viewport,
1169
+ accessibleLabel: UIStringsNotTranslate.revealViewport,
1170
+ title: UIStringsNotTranslate.viewport,
1171
+ jslog: 'viewport-widget',
1172
+ },
1173
+ [Trace.Insights.Types.InsightKeys.MODERN_HTTP]: {
1174
+ component: TimelineInsights.ModernHTTP.ModernHTTP,
1175
+ accessibleLabel: UIStringsNotTranslate.revealModernHttp,
1176
+ title: UIStringsNotTranslate.modernHttp,
1177
+ jslog: 'modern-http-widget',
1178
+ },
1179
+ [Trace.Insights.Types.InsightKeys.CHARACTER_SET]: {
1180
+ component: TimelineInsights.CharacterSet.CharacterSet,
1181
+ accessibleLabel: UIStringsNotTranslate.revealCharacterSet,
1182
+ title: UIStringsNotTranslate.characterSet,
1183
+ jslog: 'character-set-widget',
1184
+ },
974
1185
  };
975
1186
 
976
1187
  function renderInsightWidget<T extends Trace.Insights.Types.InsightModel>(
@@ -1566,7 +1777,7 @@ function renderActions(input: ChatMessageViewInput, output: ViewOutput): Lit.Lit
1566
1777
  }
1567
1778
 
1568
1779
  export class ChatMessage extends UI.Widget.Widget {
1569
- message: Message = {entity: ChatMessageEntity.USER, text: ''};
1780
+ message: Message = {entity: ChatMessageEntity.USER, text: '', id: ''};
1570
1781
  isLoading = false;
1571
1782
  isReadOnly = false;
1572
1783
  prompt = '';
@@ -155,7 +155,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
155
155
  <main @scroll=${input.handleScroll} ${ref(element => { output.mainElement = element as HTMLElement; } )}>
156
156
  ${input.messages.length > 0 ? html`
157
157
  <div class="messages-container" ${ref(input.handleMessageContainerRef)}>
158
- ${repeat(input.messages, (message, index) => {
158
+ ${repeat(input.messages, message => message.id, (message, index) => {
159
159
  const prevMessage = index > 0 ? input.messages[index - 1] : null;
160
160
  const prompt = (message.entity === ChatMessageEntity.MODEL && prevMessage?.entity === ChatMessageEntity.USER) ?
161
161
  prevMessage.text :
@@ -169,7 +169,7 @@ const DEFAULT_VIEW: View = (input, output, target) => {
169
169
  isLastMessage: index === input.messages.length - 1,
170
170
  isFirstMessage: index === 0,
171
171
  prompt,
172
- shouldShowCSSChangeSummary: message === cssChangeSummaryMessage,
172
+ shouldShowCSSChangeSummary: message.id === cssChangeSummaryMessage?.id,
173
173
  onSuggestionClick: input.handleSuggestionClick,
174
174
  onFeedbackSubmit: input.onFeedbackSubmit,
175
175
  onCopyResponseClick: input.onCopyResponseClick,
@@ -265,6 +265,16 @@ const UIStrings = {
265
265
  * @example {5} PH1
266
266
  */
267
267
  filteredMessagesInConsole: '{PH1} messages in console',
268
+ /**
269
+ * @description Tooltip for the collapse all button in the Console panel toolbar.
270
+ * Clicking this button will collapse all groups and stack traces.
271
+ */
272
+ collapseAll: 'Collapse all',
273
+ /**
274
+ * @description Tooltip for the expand all button in the Console panel toolbar.
275
+ * Clicking this button will expand all groups and stack traces.
276
+ */
277
+ expandAll: 'Expand all',
268
278
 
269
279
  } as const;
270
280
  const str_ = i18n.i18n.registerUIStrings('panels/console/ConsoleView.ts', UIStrings);
@@ -337,6 +347,8 @@ export class ConsoleView extends UI.Widget.VBox implements
337
347
  private issueResolver = new IssuesManager.IssueResolver.IssueResolver();
338
348
  #isDetached = false;
339
349
  #onIssuesCountUpdateBound = this.#onIssuesCountUpdate.bind(this);
350
+ #collapseAllButton: UI.Toolbar.ToolbarButton;
351
+ #allCollapsed = false;
340
352
  aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
341
353
  private aiCodeCompletionSummaryToolbarContainer?: HTMLElement;
342
354
  private aiCodeCompletionSummaryToolbar?: AiCodeCompletionSummaryToolbar;
@@ -428,6 +440,10 @@ export class ConsoleView extends UI.Widget.VBox implements
428
440
  i18nString(UIStrings.showConsoleSidebar), i18nString(UIStrings.hideConsoleSidebar),
429
441
  i18nString(UIStrings.consoleSidebarShown), i18nString(UIStrings.consoleSidebarHidden), 'console-sidebar'));
430
442
  toolbar.appendToolbarItem(UI.Toolbar.Toolbar.createActionButton('console.clear'));
443
+ this.#collapseAllButton =
444
+ new UI.Toolbar.ToolbarButton(i18nString(UIStrings.collapseAll), 'compress', undefined, 'console.collapse-all');
445
+ this.#collapseAllButton.addEventListener(UI.Toolbar.ToolbarButton.Events.CLICK, this.#toggleCollapseAll, this);
446
+ toolbar.appendToolbarItem(this.#collapseAllButton);
431
447
  toolbar.appendSeparator();
432
448
  toolbar.appendToolbarItem(this.consoleContextSelector.toolbarItem());
433
449
  toolbar.appendSeparator();
@@ -684,6 +700,62 @@ export class ConsoleView extends UI.Widget.VBox implements
684
700
  this.prompt.clearAiCodeCompletionCache();
685
701
  }
686
702
 
703
+ collapseAll(): void {
704
+ for (const message of this.consoleMessages) {
705
+ if (message instanceof ConsoleGroupViewMessage) {
706
+ message.setCollapsedSilent(true);
707
+ }
708
+ message.setTraceExpanded(false);
709
+ }
710
+ this.updateMessageList();
711
+ }
712
+
713
+ expandAll(): void {
714
+ for (const message of this.consoleMessages) {
715
+ if (message instanceof ConsoleGroupViewMessage) {
716
+ message.setCollapsedSilent(false);
717
+ }
718
+ message.setTraceExpanded(true);
719
+ }
720
+ this.updateMessageList();
721
+ }
722
+
723
+ #toggleCollapseAll(): void {
724
+ if (this.#allCollapsed) {
725
+ this.expandAll();
726
+ } else {
727
+ this.collapseAll();
728
+ }
729
+ this.#allCollapsed = !this.#allCollapsed;
730
+ this.#updateCollapseAllButton();
731
+ }
732
+
733
+ #updateCollapseAllButton(): void {
734
+ let hasExpandedMessages = false;
735
+ let hasCollapsedMessages = false;
736
+ for (const message of this.visibleViewMessages) {
737
+ if (message instanceof ConsoleGroupViewMessage) {
738
+ hasExpandedMessages = hasExpandedMessages || !message.collapsed();
739
+ hasCollapsedMessages = hasCollapsedMessages || message.collapsed();
740
+ }
741
+ if (message.isExpandableTrace()) {
742
+ hasExpandedMessages = hasExpandedMessages || message.isTraceExpanded();
743
+ hasCollapsedMessages = hasCollapsedMessages || !message.isTraceExpanded();
744
+ }
745
+ if (hasExpandedMessages && hasCollapsedMessages) {
746
+ break;
747
+ }
748
+ }
749
+ this.#allCollapsed = !hasExpandedMessages && hasCollapsedMessages;
750
+ if (this.#allCollapsed) {
751
+ this.#collapseAllButton.setGlyph('expand');
752
+ this.#collapseAllButton.setTitle(i18nString(UIStrings.expandAll));
753
+ } else {
754
+ this.#collapseAllButton.setGlyph('compress');
755
+ this.#collapseAllButton.setTitle(i18nString(UIStrings.collapseAll));
756
+ }
757
+ }
758
+
687
759
  #onIssuesCountUpdate(): void {
688
760
  void this.issueToolbarThrottle.schedule(async () => this.updateIssuesToolbarItem());
689
761
  this.issuesCountUpdatedForTest();
@@ -1121,11 +1193,13 @@ export class ConsoleView extends UI.Widget.VBox implements
1121
1193
  }
1122
1194
  const parentGroup = currentGroup.consoleGroup();
1123
1195
  if (parentGroup) {
1196
+ // If the parent group has its messages hidden, don't show this group.
1197
+ if (parentGroup.messagesHidden()) {
1198
+ return;
1199
+ }
1124
1200
  showGroup(parentGroup, visibleViewMessages);
1125
1201
  }
1126
- if (!parentGroup?.messagesHidden()) {
1127
- visibleViewMessages.push(currentGroup);
1128
- }
1202
+ visibleViewMessages.push(currentGroup);
1129
1203
  }
1130
1204
  }
1131
1205
 
@@ -1369,18 +1443,23 @@ export class ConsoleView extends UI.Widget.VBox implements
1369
1443
  for (const consoleMessage of this.consoleMessages) {
1370
1444
  consoleMessage.setInSimilarGroup(false);
1371
1445
  if (consoleMessage.consoleMessage().isGroupable()) {
1372
- // Since grouping similar messages is disabled, we need clear the
1373
- // reference to the artificial console group start.
1374
- consoleMessage.clearConsoleGroup();
1446
+ // Since grouping similar messages is disabled, we need to clear the
1447
+ // reference to the artificial console group start, but preserve
1448
+ // references to real console groups (console.group()/console.groupCollapsed()).
1449
+ const group = consoleMessage.consoleGroup();
1450
+ if (group && !this.consoleGroupStarts.includes(group)) {
1451
+ consoleMessage.clearConsoleGroup();
1452
+ }
1375
1453
  }
1376
1454
  this.appendMessageToEnd(
1377
1455
  consoleMessage,
1378
- true /* crbug.com/1082963: prevent collaps`e of same messages when "Group similar" is false */);
1456
+ true /* crbug.com/1082963: prevent collapse of same messages when "Group similar" is false */);
1379
1457
  }
1380
1458
  }
1381
1459
  this.updateFilterStatus();
1382
1460
  this.#searchableView.updateSearchMatchesCount(this.regexMatchRanges.length);
1383
1461
  this.highlightMatch(this.currentMatchRangeIndex, false); // Re-highlight current match without scrolling.
1462
+ this.#updateCollapseAllButton();
1384
1463
  this.viewport.invalidate();
1385
1464
  this.messagesCountElement.setAttribute(
1386
1465
  'aria-label', i18nString(UIStrings.filteredMessagesInConsole, {PH1: this.visibleViewMessages.length}));
@@ -299,6 +299,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
299
299
  protected messageIcon: Icon|null;
300
300
  private traceExpanded: boolean;
301
301
  private expandTrace: ((arg0: boolean) => void)|null;
302
+ private hasStackTrace: boolean;
302
303
  protected anchorElement: HTMLElement|null;
303
304
  protected contentElementInternal: HTMLElement|null;
304
305
  private nestingLevelMarkers: HTMLElement[]|null;
@@ -340,6 +341,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
340
341
  this.messageIcon = null;
341
342
  this.traceExpanded = false;
342
343
  this.expandTrace = null;
344
+ this.hasStackTrace = false;
343
345
  this.anchorElement = null;
344
346
  this.contentElementInternal = null;
345
347
  this.nestingLevelMarkers = null;
@@ -653,6 +655,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
653
655
  this.expandTrace(true);
654
656
  }
655
657
 
658
+ this.hasStackTrace = true;
659
+
656
660
  // @ts-expect-error
657
661
  toggleElement._expandStackTraceForTest = this.expandTrace.bind(this, true);
658
662
  return toggleElement;
@@ -1200,6 +1204,20 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
1200
1204
  return this.consoleGroupInternal;
1201
1205
  }
1202
1206
 
1207
+ isTraceExpanded(): boolean {
1208
+ return this.traceExpanded;
1209
+ }
1210
+
1211
+ isExpandableTrace(): boolean {
1212
+ return this.hasStackTrace;
1213
+ }
1214
+
1215
+ setTraceExpanded(expanded: boolean): void {
1216
+ if (this.expandTrace && this.traceExpanded !== expanded) {
1217
+ this.expandTrace(expanded);
1218
+ }
1219
+ }
1220
+
1203
1221
  setInSimilarGroup(inSimilarGroup: boolean, isLast?: boolean): void {
1204
1222
  this.inSimilarGroup = inSimilarGroup;
1205
1223
  this.lastInSimilarGroup = inSimilarGroup && Boolean(isLast);
@@ -2161,11 +2179,15 @@ export class ConsoleGroupViewMessage extends ConsoleViewMessage {
2161
2179
  }
2162
2180
 
2163
2181
  setCollapsed(collapsed: boolean): void {
2182
+ this.setCollapsedSilent(collapsed);
2183
+ this.onToggle.call(null);
2184
+ }
2185
+
2186
+ setCollapsedSilent(collapsed: boolean): void {
2164
2187
  this.collapsedInternal = collapsed;
2165
2188
  if (this.expandGroupIcon) {
2166
2189
  this.expandGroupIcon.name = this.collapsedInternal ? 'triangle-right' : 'triangle-down';
2167
2190
  }
2168
- this.onToggle.call(null);
2169
2191
  }
2170
2192
 
2171
2193
  collapsed(): boolean {