chrome-devtools-frontend 1.0.1515796 → 1.0.1516909

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 (163) hide show
  1. package/docs/contributing/infrastructure.md +131 -82
  2. package/front_end/Tests.js +3 -29
  3. package/front_end/core/common/Progress.ts +73 -55
  4. package/front_end/core/host/GdpClient.ts +1 -1
  5. package/front_end/core/host/UserMetrics.ts +5 -2
  6. package/front_end/core/protocol_client/InspectorBackend.ts +2 -0
  7. package/front_end/core/root/Runtime.ts +0 -1
  8. package/front_end/core/sdk/CSSMatchedStyles.ts +12 -10
  9. package/front_end/core/sdk/CSSModel.ts +1 -31
  10. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +27 -7
  11. package/front_end/core/sdk/DebuggerModel.ts +1 -31
  12. package/front_end/core/sdk/EnhancedTracesParser.ts +81 -50
  13. package/front_end/core/sdk/NetworkManager.ts +1 -31
  14. package/front_end/core/sdk/NetworkRequest.ts +1 -31
  15. package/front_end/core/sdk/RehydratingConnection.snapshot.txt +1003 -0
  16. package/front_end/core/sdk/RehydratingConnection.ts +13 -18
  17. package/front_end/core/sdk/RehydratingObject.ts +8 -31
  18. package/front_end/core/sdk/RemoteObject.ts +1 -31
  19. package/front_end/core/sdk/ResourceTreeModel.ts +1 -31
  20. package/front_end/core/sdk/RuntimeModel.ts +1 -31
  21. package/front_end/core/sdk/ServiceWorkerManager.ts +1 -31
  22. package/front_end/core/sdk/SourceMap.ts +1 -31
  23. package/front_end/core/sdk/TraceObject.ts +8 -3
  24. package/front_end/entrypoints/main/MainImpl.ts +1 -3
  25. package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -3
  26. package/front_end/models/ai_assistance/ConversationHandler.ts +4 -6
  27. package/front_end/models/ai_assistance/agents/AiAgent.ts +4 -1
  28. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +110 -76
  29. package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +2 -2
  30. package/front_end/models/ai_assistance/agents/StylingAgent.ts +2 -2
  31. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +178 -85
  32. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +308 -218
  33. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +100 -100
  34. package/front_end/models/ai_assistance/data_formatters/UnitFormatters.ts +10 -1
  35. package/front_end/models/ai_assistance/performance/AIContext.ts +19 -21
  36. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +24 -8
  37. package/front_end/models/badges/UserBadges.ts +38 -3
  38. package/front_end/models/bindings/ContentProviderBasedProject.ts +6 -4
  39. package/front_end/models/breakpoints/BreakpointManager.ts +3 -3
  40. package/front_end/models/formatter/FormatterWorkerPool.ts +3 -3
  41. package/front_end/models/har/Writer.ts +11 -11
  42. package/front_end/models/persistence/FileSystemWorkspaceBinding.ts +3 -3
  43. package/front_end/models/persistence/IsolatedFileSystem.ts +4 -4
  44. package/front_end/models/persistence/IsolatedFileSystemManager.ts +7 -7
  45. package/front_end/models/persistence/PersistenceImpl.ts +8 -8
  46. package/front_end/models/persistence/PlatformFileSystem.ts +1 -1
  47. package/front_end/models/trace/ModelImpl.ts +2 -16
  48. package/front_end/models/trace/Processor.ts +15 -9
  49. package/front_end/models/trace/handlers/AuctionWorkletsHandler.ts +4 -4
  50. package/front_end/models/trace/handlers/FramesHandler.ts +2 -2
  51. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -10
  52. package/front_end/models/trace/handlers/MetaHandler.ts +11 -9
  53. package/front_end/models/trace/handlers/ScreenshotsHandler.ts +1 -1
  54. package/front_end/models/trace/handlers/ScriptsHandler.ts +5 -5
  55. package/front_end/models/trace/handlers/UserInteractionsHandler.ts +2 -14
  56. package/front_end/models/trace/handlers/UserTimingsHandler.ts +3 -4
  57. package/front_end/models/trace/insights/CLSCulprits.ts +1 -1
  58. package/front_end/models/trace/insights/DocumentLatency.ts +3 -4
  59. package/front_end/models/trace/insights/DuplicatedJavaScript.ts +1 -1
  60. package/front_end/models/trace/insights/INPBreakdown.ts +1 -1
  61. package/front_end/models/trace/insights/ImageDelivery.ts +1 -1
  62. package/front_end/models/trace/insights/LCPBreakdown.ts +1 -1
  63. package/front_end/models/trace/insights/LCPDiscovery.ts +1 -1
  64. package/front_end/models/trace/insights/ModernHTTP.ts +1 -1
  65. package/front_end/models/trace/insights/NetworkDependencyTree.ts +1 -1
  66. package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
  67. package/front_end/models/trace/insights/types.ts +2 -0
  68. package/front_end/models/trace/types/TraceEvents.ts +41 -64
  69. package/front_end/models/trace_source_maps_resolver/trace_source_maps_resolver.ts +1 -1
  70. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -99
  71. package/front_end/panels/application/ServiceWorkersView.ts +0 -1
  72. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +2 -3
  73. package/front_end/panels/common/BadgeNotification.ts +46 -10
  74. package/front_end/panels/common/GdpSignUpDialog.ts +6 -3
  75. package/front_end/panels/console/ConsoleView.ts +23 -28
  76. package/front_end/panels/console/ConsoleViewport.ts +2 -2
  77. package/front_end/panels/console/consoleView.css +11 -1
  78. package/front_end/panels/coverage/CoverageView.ts +2 -2
  79. package/front_end/panels/elements/ComputedStyleWidget.ts +1 -2
  80. package/front_end/panels/elements/ElementsTreeOutline.ts +2 -2
  81. package/front_end/panels/elements/LayoutPane.ts +1 -1
  82. package/front_end/panels/elements/StyleEditorWidget.ts +8 -19
  83. package/front_end/panels/elements/StylePropertyTreeElement.ts +39 -25
  84. package/front_end/panels/elements/StylesSidebarPane.ts +2 -2
  85. package/front_end/panels/elements/stylePropertiesTreeOutline.css +4 -3
  86. package/front_end/panels/layer_viewer/Layers3DView.ts +2 -2
  87. package/front_end/panels/layers/LayerTreeModel.ts +3 -3
  88. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +4 -4
  89. package/front_end/panels/network/NetworkLogView.ts +6 -2
  90. package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
  91. package/front_end/panels/network/NetworkSearchScope.ts +6 -6
  92. package/front_end/panels/search/SearchResultsPane.ts +32 -47
  93. package/front_end/panels/search/SearchView.ts +58 -80
  94. package/front_end/panels/settings/components/SyncSection.ts +7 -2
  95. package/front_end/panels/sources/OutlineQuickOpen.ts +3 -1
  96. package/front_end/panels/sources/SourcesSearchScope.ts +4 -4
  97. package/front_end/panels/sources/TabbedEditorContainer.ts +5 -5
  98. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +10 -5
  99. package/front_end/panels/timeline/TimelineFlameChartView.ts +18 -15
  100. package/front_end/panels/timeline/TimelinePanel.ts +41 -22
  101. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -8
  102. package/front_end/panels/timeline/TracingLayerTree.ts +4 -5
  103. package/front_end/panels/timeline/components/ExportTraceOptions.ts +37 -22
  104. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +17 -7
  105. package/front_end/third_party/axe-core/README.chromium +1 -0
  106. package/front_end/third_party/codemirror/README.chromium +1 -0
  107. package/front_end/third_party/codemirror.next/README.chromium +1 -0
  108. package/front_end/third_party/csp_evaluator/README.chromium +1 -0
  109. package/front_end/third_party/diff/README.chromium +1 -0
  110. package/front_end/third_party/i18n/README.chromium +1 -0
  111. package/front_end/third_party/intl-messageformat/README.chromium +1 -0
  112. package/front_end/third_party/json5/README.chromium +1 -0
  113. package/front_end/third_party/legacy-javascript/README.chromium +1 -0
  114. package/front_end/third_party/lighthouse/README.chromium +1 -0
  115. package/front_end/third_party/lit/README.chromium +1 -0
  116. package/front_end/third_party/marked/README.chromium +1 -0
  117. package/front_end/third_party/puppeteer/README.chromium +2 -2
  118. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
  119. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js +0 -20
  120. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
  122. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  128. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +2 -23
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +0 -20
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +1 -1
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +1 -1
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  136. package/front_end/third_party/puppeteer/package/package.json +1 -1
  137. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +1 -21
  138. package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
  139. package/front_end/third_party/puppeteer/package/src/revisions.ts +1 -1
  140. package/front_end/third_party/puppeteer-replay/README.chromium +1 -0
  141. package/front_end/third_party/third-party-web/README.chromium +1 -0
  142. package/front_end/third_party/vscode.web-custom-data/README.chromium +1 -0
  143. package/front_end/third_party/wasmparser/README.chromium +1 -0
  144. package/front_end/third_party/web-vitals/README.chromium +1 -0
  145. package/front_end/ui/components/text_editor/config.ts +30 -1
  146. package/front_end/ui/components/tooltips/Tooltip.ts +18 -4
  147. package/front_end/ui/legacy/ContextMenu.ts +2 -2
  148. package/front_end/ui/legacy/GlassPane.ts +7 -3
  149. package/front_end/ui/legacy/ProgressIndicator.ts +29 -16
  150. package/front_end/ui/legacy/TabbedPane.ts +2 -2
  151. package/front_end/ui/legacy/Treeoutline.ts +10 -5
  152. package/front_end/ui/legacy/UIUtils.ts +42 -10
  153. package/front_end/ui/legacy/components/color_picker/Spectrum.ts +14 -14
  154. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +6 -6
  155. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +3 -29
  156. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +14 -14
  157. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  158. package/inspector_overlay/highlight_common.ts +1 -27
  159. package/inspector_overlay/highlight_grid_common.ts +1 -27
  160. package/inspector_overlay/tool_highlight.ts +1 -27
  161. package/inspector_overlay/tool_persistent.ts +1 -27
  162. package/inspector_overlay/tool_source_order.ts +1 -27
  163. package/package.json +1 -1
@@ -132,10 +132,6 @@ const UIStringsNotTranslate = {
132
132
  * @description Placeholder text for the chat UI input.
133
133
  */
134
134
  inputPlaceholderForFile: 'Ask a question about the selected file',
135
- /**
136
- * @description Placeholder text for the chat UI input.
137
- */
138
- inputPlaceholderForPerformance: 'Ask a question about the selected item and its call tree',
139
135
  /**
140
136
  * @description Placeholder text for the chat UI input.
141
137
  */
@@ -152,18 +148,6 @@ const UIStringsNotTranslate = {
152
148
  * @description Placeholder text for the chat UI input when there is no context selected.
153
149
  */
154
150
  inputPlaceholderForFileNoContext: 'Select a file to ask a question',
155
- /**
156
- * @description Placeholder text for the chat UI input when there is no context selected.
157
- */
158
- inputPlaceholderForPerformanceNoContext: 'Select an item to ask a question',
159
- /**
160
- * @description Placeholder text for the chat UI input.
161
- */
162
- inputPlaceholderForPerformanceInsights: 'Ask a question about the selected performance insight',
163
- /**
164
- * @description Placeholder text for the chat UI input.
165
- */
166
- inputPlaceholderForPerformanceInsightsNoContext: 'Select a performance insight to ask a question',
167
151
  /**
168
152
  * @description Placeholder text for the chat UI input.
169
153
  */
@@ -171,7 +155,7 @@ const UIStringsNotTranslate = {
171
155
  /**
172
156
  *@description Placeholder text for the chat UI input.
173
157
  */
174
- inputPlaceholderForPerformanceTraceNoContext: 'Select a performance trace to ask a question',
158
+ inputPlaceholderForPerformanceTraceNoContext: 'Record or select a performance trace to ask a question',
175
159
  /**
176
160
  * @description Disclaimer text right after the chat input.
177
161
  */
@@ -236,7 +220,7 @@ function selectedElementFilter(maybeNode: SDK.DOMModel.DOMNode|null): SDK.DOMMod
236
220
 
237
221
  async function getEmptyStateSuggestions(
238
222
  context: AiAssistanceModel.ConversationContext<unknown>|null,
239
- conversationType?: AiAssistanceModel.ConversationType): Promise<AiAssistanceModel.ConversationSuggestion[]> {
223
+ conversation?: AiAssistanceModel.Conversation): Promise<AiAssistanceModel.ConversationSuggestion[]> {
240
224
  if (context) {
241
225
  const specialSuggestions = await context.getSuggestions();
242
226
 
@@ -245,11 +229,11 @@ async function getEmptyStateSuggestions(
245
229
  }
246
230
  }
247
231
 
248
- if (!conversationType) {
232
+ if (!conversation?.type || conversation.isReadOnly) {
249
233
  return [];
250
234
  }
251
235
 
252
- switch (conversationType) {
236
+ switch (conversation.type) {
253
237
  case AiAssistanceModel.ConversationType.STYLING:
254
238
  return [
255
239
  {title: 'What can you help me with?', jslogContext: 'styling-default'},
@@ -268,28 +252,14 @@ async function getEmptyStateSuggestions(
268
252
  {title: 'Are there any security headers present?', jslogContext: 'network-default'},
269
253
  {title: 'Why is the request failing?', jslogContext: 'network-default'},
270
254
  ];
271
- case AiAssistanceModel.ConversationType.PERFORMANCE_FULL:
255
+ case AiAssistanceModel.ConversationType.PERFORMANCE: {
272
256
  return [
273
257
  {title: 'What performance issues exist with my page?', jslogContext: 'performance-default'},
274
258
  ];
275
- case AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT:
276
- case AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE: {
277
- const focus = context?.getItem() as AiAssistanceModel.AgentFocus | null;
278
- if (focus?.data.type === 'call-tree') {
279
- return [
280
- {title: 'What\'s the purpose of this work?', jslogContext: 'performance-default'},
281
- {title: 'Where is time being spent?', jslogContext: 'performance-default'},
282
- {title: 'How can I optimize this?', jslogContext: 'performance-default'},
283
- ];
284
- }
285
-
286
- return [
287
- {title: 'Help me optimize my page load performance', jslogContext: 'performance-insights-default'},
288
- ];
289
259
  }
290
260
 
291
261
  default:
292
- Platform.assertNever(conversationType, 'Unknown conversation type');
262
+ Platform.assertNever(conversation.type, 'Unknown conversation type');
293
263
  }
294
264
  }
295
265
 
@@ -619,15 +589,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
619
589
  const isSourcesPanelVisible = viewManager.isViewVisible('sources');
620
590
  const isPerformancePanelVisible = viewManager.isViewVisible('timeline');
621
591
 
622
- // Check if the user has an insight expanded in the performance panel sidebar.
623
- // If they have, we default to the Insights agent; otherwise we fallback to
624
- // the regular Performance agent.
625
- // Note that we do not listen to this flavor changing; this code is here to
626
- // ensure that by default we do not pick the Insights agent if the user has
627
- // just imported a trace and not done anything else. It doesn't make sense
628
- // to select the Insights AI agent in that case.
629
- const userHasExpandedPerfInsight =
630
- Boolean(UI.Context.Context.instance().flavor(TimelinePanel.TimelinePanel.SelectedInsight));
631
592
  let targetConversationType: AiAssistanceModel.ConversationType|undefined = undefined;
632
593
  if (isElementsPanelVisible && hostConfig.devToolsFreestyler?.enabled) {
633
594
  targetConversationType = AiAssistanceModel.ConversationType.STYLING;
@@ -635,12 +596,8 @@ export class AiAssistancePanel extends UI.Panel.Panel {
635
596
  targetConversationType = AiAssistanceModel.ConversationType.NETWORK;
636
597
  } else if (isSourcesPanelVisible && hostConfig.devToolsAiAssistanceFileAgent?.enabled) {
637
598
  targetConversationType = AiAssistanceModel.ConversationType.FILE;
638
- } else if (
639
- isPerformancePanelVisible && hostConfig.devToolsAiAssistancePerformanceAgent?.enabled &&
640
- hostConfig.devToolsAiAssistancePerformanceAgent?.insightsEnabled && userHasExpandedPerfInsight) {
641
- targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT;
642
599
  } else if (isPerformancePanelVisible && hostConfig.devToolsAiAssistancePerformanceAgent?.enabled) {
643
- targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE;
600
+ targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE;
644
601
  }
645
602
 
646
603
  if (this.#conversation?.type === targetConversationType) {
@@ -845,25 +802,6 @@ export class AiAssistancePanel extends UI.Panel.Panel {
845
802
  this.#selectedPerformanceTrace =
846
803
  Boolean(ev.data) ? new AiAssistanceModel.PerformanceTraceContext(ev.data) : null;
847
804
 
848
- let conversationType: AiAssistanceModel.ConversationType|undefined;
849
- if (ev.data) {
850
- if (ev.data.data.type === 'full') {
851
- conversationType = AiAssistanceModel.ConversationType.PERFORMANCE_FULL;
852
- } else if (ev.data.data.type === 'insight') {
853
- conversationType = AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT;
854
- } else if (ev.data.data.type === 'call-tree') {
855
- conversationType = AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE;
856
- } else {
857
- Platform.assertNever(ev.data.data, 'Unknown agent focus');
858
- }
859
- }
860
-
861
- let agent = this.#conversationAgent;
862
- if (conversationType && agent instanceof AiAssistanceModel.PerformanceAgent &&
863
- agent.getConversationType() !== conversationType) {
864
- agent = this.#conversationHandler.createAgent(conversationType);
865
- }
866
-
867
805
  this.#updateConversationState({agent: this.#conversationAgent});
868
806
  };
869
807
 
@@ -898,7 +836,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
898
836
  }
899
837
 
900
838
  override async performUpdate(): Promise<void> {
901
- const emptyStateSuggestions = await getEmptyStateSuggestions(this.#selectedContext, this.#conversation?.type);
839
+ const emptyStateSuggestions = await getEmptyStateSuggestions(this.#selectedContext, this.#conversation);
902
840
 
903
841
  this.view(
904
842
  {
@@ -1039,21 +977,16 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1039
977
  case AiAssistanceModel.ConversationType.NETWORK:
1040
978
  return this.#selectedContext ? lockedString(UIStringsNotTranslate.inputPlaceholderForNetwork) :
1041
979
  lockedString(UIStringsNotTranslate.inputPlaceholderForNetworkNoContext);
1042
- case AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE: {
980
+ case AiAssistanceModel.ConversationType.PERFORMANCE: {
1043
981
  const perfPanel = UI.Context.Context.instance().flavor(TimelinePanel.TimelinePanel.TimelinePanel);
1044
982
  if (perfPanel?.hasActiveTrace()) {
1045
- return this.#selectedContext ? lockedString(UIStringsNotTranslate.inputPlaceholderForPerformance) :
1046
- lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceNoContext);
983
+ return this.#selectedContext ?
984
+ lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceTrace) :
985
+ lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceTraceNoContext);
1047
986
  }
987
+
1048
988
  return lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceWithNoRecording);
1049
989
  }
1050
- case AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT:
1051
- return this.#selectedContext ?
1052
- lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceInsights) :
1053
- lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceInsightsNoContext);
1054
- case AiAssistanceModel.ConversationType.PERFORMANCE_FULL:
1055
- return this.#selectedContext ? lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceTrace) :
1056
- lockedString(UIStringsNotTranslate.inputPlaceholderForPerformanceTraceNoContext);
1057
990
  }
1058
991
  }
1059
992
 
@@ -1084,9 +1017,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1084
1017
 
1085
1018
  // It is deliberate that both Performance agents use the same disclaimer
1086
1019
  // text and this has been approved by Privacy.
1087
- case AiAssistanceModel.ConversationType.PERFORMANCE_FULL:
1088
- case AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE:
1089
- case AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT:
1020
+ case AiAssistanceModel.ConversationType.PERFORMANCE:
1090
1021
  if (noLogging) {
1091
1022
  return lockedString(UIStringsNotTranslate.inputDisclaimerForPerformanceEnterpriseNoLogging);
1092
1023
  }
@@ -1121,18 +1052,14 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1121
1052
  }
1122
1053
  if (context instanceof AiAssistanceModel.PerformanceTraceContext) {
1123
1054
  const focus = context.getItem().data;
1124
- if (focus.type === 'full') {
1125
- return;
1126
- }
1127
- if (focus.type === 'call-tree') {
1055
+ if (focus.callTree) {
1128
1056
  const event = focus.callTree.selectedNode?.event ?? focus.callTree.rootNode.event;
1129
1057
  const trace = new SDK.TraceObject.RevealableEvent(event);
1130
1058
  return Common.Revealer.reveal(trace);
1131
1059
  }
1132
- if (focus.type === 'insight') {
1060
+ if (focus.insight) {
1133
1061
  return Common.Revealer.reveal(focus.insight);
1134
1062
  }
1135
- Platform.assertNever(focus, 'Unknown agent focus');
1136
1063
  }
1137
1064
  // Node picker is using linkifier.
1138
1065
  }
@@ -1169,17 +1096,17 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1169
1096
  }
1170
1097
  case 'drjones.performance-panel-context': {
1171
1098
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceOpenedFromPerformancePanelCallTree);
1172
- targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE;
1099
+ targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE;
1173
1100
  break;
1174
1101
  }
1175
1102
  case 'drjones.performance-insight-context': {
1176
1103
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceOpenedFromPerformanceInsight);
1177
- targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT;
1104
+ targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE;
1178
1105
  break;
1179
1106
  }
1180
1107
  case 'drjones.performance-panel-full-context': {
1181
1108
  Host.userMetrics.actionTaken(Host.UserMetrics.Action.AiAssistanceOpenedFromPerformanceFullButton);
1182
- targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE_FULL;
1109
+ targetConversationType = AiAssistanceModel.ConversationType.PERFORMANCE;
1183
1110
  break;
1184
1111
  }
1185
1112
  case 'drjones.sources-floating-button': {
@@ -1200,10 +1127,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1200
1127
 
1201
1128
  let agent = this.#conversationAgent;
1202
1129
  if (!this.#conversation || !this.#conversationAgent || this.#conversation.type !== targetConversationType ||
1203
- this.#conversation?.isEmpty ||
1204
- targetConversationType === AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE ||
1205
- (agent instanceof AiAssistanceModel.PerformanceAgent &&
1206
- agent.getConversationType() !== targetConversationType)) {
1130
+ this.#conversation?.isEmpty) {
1207
1131
  agent = this.#conversationHandler.createAgent(targetConversationType, this.#changeManager);
1208
1132
  }
1209
1133
  this.#updateConversationState({agent});
@@ -1448,9 +1372,7 @@ export class AiAssistancePanel extends UI.Panel.Panel {
1448
1372
  case AiAssistanceModel.ConversationType.NETWORK:
1449
1373
  context = this.#selectedRequest;
1450
1374
  break;
1451
- case AiAssistanceModel.ConversationType.PERFORMANCE_FULL:
1452
- case AiAssistanceModel.ConversationType.PERFORMANCE_CALL_TREE:
1453
- case AiAssistanceModel.ConversationType.PERFORMANCE_INSIGHT:
1375
+ case AiAssistanceModel.ConversationType.PERFORMANCE:
1454
1376
  context = this.#selectedPerformanceTrace;
1455
1377
  break;
1456
1378
  }
@@ -487,7 +487,6 @@ export class Section {
487
487
  this.routerView = new ApplicationComponents.ServiceWorkerRouterView.ServiceWorkerRouterView();
488
488
  this.networkRequests = new Buttons.Button.Button();
489
489
  this.networkRequests.data = {
490
- iconName: 'bottom-panel-open',
491
490
  variant: Buttons.Button.Variant.TEXT,
492
491
  title: i18nString(UIStrings.networkRequests),
493
492
  jslogContext: 'show-network-requests',
@@ -176,7 +176,6 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
176
176
  }
177
177
  };
178
178
 
179
- const {on} = UI.UIUtils.HTMLElementWithLightDOMTemplate;
180
179
  const classes =
181
180
  (breakpoint: SDK.CategorizedBreakpoint.CategorizedBreakpoint): ReturnType<typeof Lit.Directives.classMap> =>
182
181
  Lit.Directives.classMap({
@@ -239,7 +238,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
239
238
  ?indeterminate=${breakpoints.some(breakpoint => !breakpoint.enabled()) &&
240
239
  breakpoints.some(breakpoint => breakpoint.enabled())}
241
240
  ?checked=${!breakpoints.some(breakpoint => !breakpoint.enabled())}
242
- @change=${on((e: Event) => onCheckboxClicked(e, category))}
241
+ @change=${(e: Event) => onCheckboxClicked(e, category)}
243
242
  >${getLocalizedCategory(category)}</devtools-checkbox>
244
243
  <ul
245
244
  role="group"
@@ -257,7 +256,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
257
256
  ?checked=${breakpoint.enabled()}
258
257
  aria-description=${breakpoint === input.highlightedItem ? i18nString(UIStrings.breakpointHit)
259
258
  : Lit.nothing}
260
- @change=${on((e: Event) => onCheckboxClicked(e, breakpoint))}
259
+ @change=${(e: Event) => onCheckboxClicked(e, breakpoint)}
261
260
  >${Sources.CategorizedBreakpointL10n.getLocalizedBreakpointName(breakpoint.name)}</devtools-checkbox>
262
261
  </li>`)}
263
262
  </ul>
@@ -69,6 +69,8 @@ const lockedString = i18n.i18n.lockedString;
69
69
 
70
70
  const LEFT_OFFSET = 5;
71
71
  const BOTTOM_OFFSET = 5;
72
+ const AUTO_CLOSE_TIME_IN_MS = 30000;
73
+
72
74
  export interface BadgeNotificationAction {
73
75
  label: string;
74
76
  jslogContext?: string;
@@ -80,10 +82,11 @@ export interface BadgeNotificationProperties {
80
82
  message: HTMLElement|string;
81
83
  imageUri: string;
82
84
  actions: BadgeNotificationAction[];
85
+ isStarterBadge: boolean;
83
86
  }
84
87
 
85
88
  export interface ViewInput extends BadgeNotificationProperties {
86
- onCloseClick: () => void;
89
+ onDismissClick: () => void;
87
90
  }
88
91
 
89
92
  // clang-format off
@@ -101,7 +104,7 @@ const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement)
101
104
 
102
105
  const crossButton = html`<devtools-button
103
106
  class="dismiss notification-button"
104
- @click=${input.onCloseClick}
107
+ @click=${input.onDismissClick}
105
108
  jslog=${VisualLogging.action('badge-notification.dismiss').track({click: true})}
106
109
  aria-label=${i18nString(UIStrings.close)}
107
110
  .iconName=${'cross'}
@@ -138,9 +141,10 @@ export class BadgeNotification extends UI.Widget.Widget {
138
141
  message: HTMLElement|string = '';
139
142
  imageUri = '';
140
143
  actions: BadgeNotificationAction[] = [];
144
+ isStarterBadge = false;
141
145
 
146
+ #autoCloseTimeout?: number;
142
147
  #view: View;
143
-
144
148
  constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
145
149
  super(element);
146
150
  this.#view = view;
@@ -170,12 +174,18 @@ export class BadgeNotification extends UI.Widget.Widget {
170
174
  this.message = properties.message;
171
175
  this.imageUri = properties.imageUri;
172
176
  this.actions = properties.actions;
177
+ this.isStarterBadge = properties.isStarterBadge;
173
178
  this.requestUpdate();
174
179
  this.show(document.body);
175
180
 
176
181
  void this.updateComplete.then(() => {
177
182
  this.#positionNotification();
178
183
  });
184
+
185
+ if (this.#autoCloseTimeout) {
186
+ window.clearTimeout(this.#autoCloseTimeout);
187
+ }
188
+ this.#autoCloseTimeout = window.setTimeout(this.#onAutoClose, AUTO_CLOSE_TIME_IN_MS);
179
189
  }
180
190
 
181
191
  async #presentStarterBadge(badge: Badges.Badge): Promise<void> {
@@ -201,17 +211,21 @@ export class BadgeNotification extends UI.Widget.Widget {
201
211
  actions: [
202
212
  {
203
213
  label: i18nString(UIStrings.remindMeLater),
204
- onClick: () => {/* To implement */},
214
+ onClick: () => {
215
+ this.detach();
216
+ Badges.UserBadges.instance().snoozeStarterBadge();
217
+ },
205
218
  },
206
219
  {
207
220
  label: i18nString(UIStrings.receiveBadges),
208
221
  onClick: () => {
209
- this.#close();
222
+ this.detach();
210
223
  revealBadgeSettings();
211
224
  }
212
225
  }
213
226
  ],
214
227
  imageUri: badge.imageUri,
228
+ isStarterBadge: true,
215
229
  });
216
230
  return;
217
231
  }
@@ -223,17 +237,21 @@ export class BadgeNotification extends UI.Widget.Widget {
223
237
  actions: [
224
238
  {
225
239
  label: i18nString(UIStrings.remindMeLater),
226
- onClick: () => {/* TODO(ergunsh): Implement */},
240
+ onClick: () => {
241
+ this.detach();
242
+ Badges.UserBadges.instance().snoozeStarterBadge();
243
+ },
227
244
  },
228
245
  {
229
246
  label: i18nString(UIStrings.createProfile),
230
247
  onClick: () => {
231
- this.#close();
248
+ this.detach();
232
249
  GdpSignUpDialog.GdpSignUpDialog.show();
233
250
  }
234
251
  }
235
252
  ],
236
253
  imageUri: badge.imageUri,
254
+ isStarterBadge: true,
237
255
  });
238
256
  }
239
257
 
@@ -244,7 +262,7 @@ export class BadgeNotification extends UI.Widget.Widget {
244
262
  {
245
263
  label: i18nString(UIStrings.manageSettings),
246
264
  onClick: () => {
247
- this.#close();
265
+ this.detach();
248
266
  revealBadgeSettings();
249
267
  },
250
268
  },
@@ -256,11 +274,28 @@ export class BadgeNotification extends UI.Widget.Widget {
256
274
  }
257
275
  ],
258
276
  imageUri: badge.imageUri,
277
+ isStarterBadge: badge.isStarterBadge,
259
278
  });
260
279
  }
261
280
 
262
- #close = (): void => {
281
+ override onDetach(): void {
282
+ window.clearTimeout(this.#autoCloseTimeout);
283
+ }
284
+
285
+ #onDismissClick = (): void => {
286
+ this.detach();
287
+
288
+ if (this.isStarterBadge) {
289
+ Badges.UserBadges.instance().dismissStarterBadge();
290
+ }
291
+ };
292
+
293
+ #onAutoClose = (): void => {
263
294
  this.detach();
295
+
296
+ if (this.isStarterBadge) {
297
+ Badges.UserBadges.instance().snoozeStarterBadge();
298
+ }
264
299
  };
265
300
 
266
301
  override wasShown(): void {
@@ -273,7 +308,8 @@ export class BadgeNotification extends UI.Widget.Widget {
273
308
  message: this.message,
274
309
  imageUri: this.imageUri,
275
310
  actions: this.actions,
276
- onCloseClick: this.#close,
311
+ isStarterBadge: this.isStarterBadge,
312
+ onDismissClick: this.#onDismissClick,
277
313
  };
278
314
  this.#view(viewInput, undefined, this.contentElement);
279
315
  }
@@ -193,10 +193,12 @@ export class GdpSignUpDialog extends UI.Widget.VBox {
193
193
  #dialog: UI.Dialog.Dialog;
194
194
  #keepMeUpdated = false;
195
195
  #isSigningUp = false;
196
+ #onSuccess?: () => void;
196
197
 
197
- constructor(options: {dialog: UI.Dialog.Dialog}, view?: View) {
198
+ constructor(options: {dialog: UI.Dialog.Dialog, onSuccess?: () => void}, view?: View) {
198
199
  super();
199
200
  this.#dialog = options.dialog;
201
+ this.#onSuccess = options.onSuccess;
200
202
  this.#view = view ?? DEFAULT_VIEW;
201
203
  this.requestUpdate();
202
204
  }
@@ -215,6 +217,7 @@ export class GdpSignUpDialog extends UI.Widget.VBox {
215
217
  Common.Settings.Settings.instance().moduleSetting('receive-gdp-badges').set(true);
216
218
  await Badges.UserBadges.instance().initialize();
217
219
  Badges.UserBadges.instance().recordAction(Badges.BadgeAction.GDP_SIGN_UP_COMPLETE);
220
+ this.#onSuccess?.();
218
221
  this.#dialog.hide();
219
222
  } else {
220
223
  Snackbars.Snackbar.Snackbar.show({message: i18nString(UIStrings.signUpFailed)}, this.#dialog.contentElement);
@@ -240,14 +243,14 @@ export class GdpSignUpDialog extends UI.Widget.VBox {
240
243
  this.#view(viewInput, undefined, this.contentElement);
241
244
  }
242
245
 
243
- static show(): void {
246
+ static show({onSuccess}: {onSuccess?: () => void} = {}): void {
244
247
  const dialog = new UI.Dialog.Dialog();
245
248
  dialog.setAriaLabel(i18nString(UIStrings.gdpDialogAriaLabel));
246
249
  dialog.setMaxContentSize(new Geometry.Size(384, 500));
247
250
  dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SET_EXACT_WIDTH_MAX_HEIGHT);
248
251
  dialog.setDimmed(true);
249
252
 
250
- new GdpSignUpDialog({dialog}).show(dialog.contentElement);
253
+ new GdpSignUpDialog({dialog, onSuccess}).show(dialog.contentElement);
251
254
  dialog.show(undefined, /* stack */ true);
252
255
  }
253
256
  }
@@ -322,7 +322,7 @@ export class ConsoleView extends UI.Widget.VBox implements
322
322
  private buildHiddenCacheTimeout?: number;
323
323
  private searchShouldJumpBackwards?: boolean;
324
324
  private searchProgressIndicator?: UI.ProgressIndicator.ProgressIndicator;
325
- private innerSearchTimeoutId?: number;
325
+ #searchTimeoutId?: number;
326
326
  private muteViewportUpdates?: boolean;
327
327
  private waitForScrollTimeout?: number;
328
328
  private issueCounter: IssueCounter.IssueCounter.IssueCounter;
@@ -1051,18 +1051,13 @@ export class ConsoleView extends UI.Widget.VBox implements
1051
1051
  return;
1052
1052
  }
1053
1053
 
1054
- // Track any adjacent messages.
1055
- const originatingMessage = viewMessage.consoleMessage().originatingMessage();
1056
- const adjacent = Boolean(originatingMessage && lastMessage?.consoleMessage() === originatingMessage);
1057
- viewMessage.setAdjacentUserCommandResult(adjacent);
1058
-
1059
- // Ensure any parent groups for this message are shown.
1060
1054
  const currentGroup = viewMessage.consoleGroup();
1061
- showGroup(currentGroup, this.visibleViewMessages);
1062
1055
 
1063
- // Determine whether this message should actually be visible.
1064
- const shouldShowMessage = !currentGroup?.messagesHidden();
1065
- if (shouldShowMessage) {
1056
+ if (!currentGroup?.messagesHidden()) {
1057
+ const originatingMessage = viewMessage.consoleMessage().originatingMessage();
1058
+ const adjacent = Boolean(originatingMessage && lastMessage?.consoleMessage() === originatingMessage);
1059
+ viewMessage.setAdjacentUserCommandResult(adjacent);
1060
+ showGroup(currentGroup, this.visibleViewMessages);
1066
1061
  this.visibleViewMessages.push(viewMessage);
1067
1062
  this.searchMessage(this.visibleViewMessages.length - 1);
1068
1063
  }
@@ -1216,8 +1211,8 @@ export class ConsoleView extends UI.Widget.VBox implements
1216
1211
  const stream = new Bindings.FileUtils.FileOutputStream();
1217
1212
 
1218
1213
  const progressIndicator = document.createElement('devtools-progress');
1219
- progressIndicator.setTitle(i18nString(UIStrings.writingFile));
1220
- progressIndicator.setTotalWork(this.itemCount());
1214
+ progressIndicator.title = i18nString(UIStrings.writingFile);
1215
+ progressIndicator.totalWork = this.itemCount();
1221
1216
 
1222
1217
  const chunkSize = 350;
1223
1218
 
@@ -1227,7 +1222,7 @@ export class ConsoleView extends UI.Widget.VBox implements
1227
1222
  this.progressToolbarItem.element.appendChild(progressIndicator);
1228
1223
 
1229
1224
  let messageIndex = 0;
1230
- while (messageIndex < this.itemCount() && !progressIndicator.isCanceled()) {
1225
+ while (messageIndex < this.itemCount() && !progressIndicator.canceled) {
1231
1226
  const messageContents = [];
1232
1227
  let i;
1233
1228
  for (i = 0; i < chunkSize && i + messageIndex < this.itemCount(); ++i) {
@@ -1236,11 +1231,11 @@ export class ConsoleView extends UI.Widget.VBox implements
1236
1231
  }
1237
1232
  messageIndex += i;
1238
1233
  await stream.write(messageContents.join('\n') + '\n');
1239
- progressIndicator.setWorked(messageIndex);
1234
+ progressIndicator.worked = messageIndex;
1240
1235
  }
1241
1236
 
1242
1237
  void stream.close();
1243
- progressIndicator.done();
1238
+ progressIndicator.done = true;
1244
1239
  }
1245
1240
 
1246
1241
  private async copyConsole(): Promise<void> {
@@ -1519,21 +1514,21 @@ export class ConsoleView extends UI.Widget.VBox implements
1519
1514
  }
1520
1515
 
1521
1516
  this.searchProgressIndicator = document.createElement('devtools-progress');
1522
- this.searchProgressIndicator.setTitle(i18nString(UIStrings.searching));
1523
- this.searchProgressIndicator.setTotalWork(this.visibleViewMessages.length);
1517
+ this.searchProgressIndicator.title = i18nString(UIStrings.searching);
1518
+ this.searchProgressIndicator.totalWork = this.visibleViewMessages.length;
1524
1519
  this.progressToolbarItem.element.appendChild(this.searchProgressIndicator);
1525
1520
 
1526
- this.innerSearch(0);
1521
+ this.#search(0);
1527
1522
  }
1528
1523
 
1529
1524
  private cleanupAfterSearch(): void {
1530
1525
  delete this.searchShouldJumpBackwards;
1531
- if (this.innerSearchTimeoutId) {
1532
- clearTimeout(this.innerSearchTimeoutId);
1533
- delete this.innerSearchTimeoutId;
1526
+ if (this.#searchTimeoutId) {
1527
+ clearTimeout(this.#searchTimeoutId);
1528
+ this.#searchTimeoutId = undefined;
1534
1529
  }
1535
1530
  if (this.searchProgressIndicator) {
1536
- this.searchProgressIndicator.done();
1531
+ this.searchProgressIndicator.done = true;
1537
1532
  delete this.searchProgressIndicator;
1538
1533
  }
1539
1534
  }
@@ -1542,9 +1537,9 @@ export class ConsoleView extends UI.Widget.VBox implements
1542
1537
  // This method is sniffed in tests.
1543
1538
  }
1544
1539
 
1545
- private innerSearch(index: number): void {
1546
- delete this.innerSearchTimeoutId;
1547
- if (this.searchProgressIndicator?.isCanceled()) {
1540
+ #search(index: number): void {
1541
+ this.#searchTimeoutId = undefined;
1542
+ if (this.searchProgressIndicator?.canceled) {
1548
1543
  this.cleanupAfterSearch();
1549
1544
  return;
1550
1545
  }
@@ -1566,9 +1561,9 @@ export class ConsoleView extends UI.Widget.VBox implements
1566
1561
  return;
1567
1562
  }
1568
1563
 
1569
- this.innerSearchTimeoutId = window.setTimeout(this.innerSearch.bind(this, index), 100);
1564
+ this.#searchTimeoutId = window.setTimeout(this.#search.bind(this, index), 100);
1570
1565
  if (this.searchProgressIndicator) {
1571
- this.searchProgressIndicator.setWorked(index);
1566
+ this.searchProgressIndicator.worked = index;
1572
1567
  }
1573
1568
  }
1574
1569
 
@@ -435,13 +435,13 @@ export class ConsoleViewport {
435
435
 
436
436
  refresh(): void {
437
437
  this.observer.disconnect();
438
- this.innerRefresh();
438
+ this.#refresh();
439
439
  if (this.#stickToBottom) {
440
440
  this.observer.observe(this.#contentElement, this.observerConfig);
441
441
  }
442
442
  }
443
443
 
444
- private innerRefresh(): void {
444
+ #refresh(): void {
445
445
  if (!this.visibleHeight()) {
446
446
  return;
447
447
  } // Do nothing for invisible controls.
@@ -325,14 +325,24 @@
325
325
  .console-view-object-properties-section {
326
326
  padding: 0;
327
327
  position: relative;
328
- vertical-align: top;
329
328
  color: inherit;
330
329
  display: inline-block;
331
330
  overflow-wrap: break-word;
332
331
  max-width: 100%;
332
+ vertical-align: top;
333
333
  margin-top: -1.5px;
334
334
  }
335
335
 
336
+ /* Console content is rendered in "Noto Sans Mono" on Linux, which has a
337
+ * different actual line-height than the fonts used on Windows or MacOS.
338
+ * "vertical-align: middle" breaks the layout when expanding an object such
339
+ * that it spans multiple lines. We therefore align to the top, and use a
340
+ * different "margin-top" on Linux to compensate for the line-height difference.
341
+ */
342
+ .platform-linux .console-view-object-properties-section {
343
+ margin-top: 0;
344
+ }
345
+
336
346
  .info-note {
337
347
  background-color: var(--sys-color-tonal-container);
338
348
  }
@@ -643,12 +643,12 @@ export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
643
643
  const view = UI.ViewManager.ViewManager.instance().view(coverageViewId);
644
644
  return view?.widget();
645
645
  })
646
- .then(widget => this.innerHandleAction(widget as CoverageView, actionId));
646
+ .then(widget => this.#handleAction(widget as CoverageView, actionId));
647
647
 
648
648
  return true;
649
649
  }
650
650
 
651
- private innerHandleAction(coverageView: CoverageView, actionId: string): void {
651
+ #handleAction(coverageView: CoverageView, actionId: string): void {
652
652
  switch (actionId) {
653
653
  case 'coverage.toggle-recording':
654
654
  coverageView.toggleRecording();