chrome-devtools-frontend 1.0.1515988 → 1.0.1518653

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 (122) hide show
  1. package/docs/checklist/README.md +2 -2
  2. package/docs/checklist/javascript.md +1 -1
  3. package/docs/contributing/README.md +1 -1
  4. package/docs/contributing/settings-experiments-features.md +9 -8
  5. package/docs/cookbook/devtools_on_devtools.md +2 -2
  6. package/docs/cookbook/localization.md +10 -10
  7. package/docs/devtools-protocol.md +9 -8
  8. package/docs/ecosystem/automatic_workspace_folders.md +3 -3
  9. package/docs/get_the_code.md +0 -2
  10. package/docs/styleguide/ux/components.md +166 -85
  11. package/docs/styleguide/ux/numbers.md +3 -4
  12. package/front_end/core/common/README.md +13 -12
  13. package/front_end/core/host/GdpClient.ts +16 -1
  14. package/front_end/core/host/UserMetrics.ts +8 -2
  15. package/front_end/core/root/Runtime.ts +13 -0
  16. package/front_end/core/sdk/CSSMatchedStyles.ts +5 -1
  17. package/front_end/entrypoints/main/MainImpl.ts +6 -3
  18. package/front_end/generated/InspectorBackendCommands.js +10 -7
  19. package/front_end/generated/SupportedCSSProperties.js +21 -7
  20. package/front_end/generated/protocol-mapping.d.ts +16 -1
  21. package/front_end/generated/protocol-proxy-api.d.ts +13 -1
  22. package/front_end/generated/protocol.ts +95 -0
  23. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +170 -54
  24. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +14 -181
  25. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +13 -315
  26. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +224 -50
  27. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +310 -11
  28. package/front_end/models/ai_assistance/performance/AIContext.ts +15 -2
  29. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +41 -19
  30. package/front_end/models/badges/Badge.ts +8 -3
  31. package/front_end/models/badges/CodeWhispererBadge.ts +2 -4
  32. package/front_end/models/badges/StarterBadge.ts +2 -2
  33. package/front_end/models/badges/UserBadges.ts +59 -6
  34. package/front_end/models/formatter/FormatterWorkerPool.ts +3 -3
  35. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  36. package/front_end/models/trace/README.md +28 -1
  37. package/front_end/models/trace/handlers/UserTimingsHandler.ts +1 -1
  38. package/front_end/models/trace/helpers/Trace.ts +99 -43
  39. package/front_end/models/trace/types/TraceEvents.ts +9 -0
  40. package/front_end/panels/accessibility/ARIAAttributesView.ts +113 -191
  41. package/front_end/panels/accessibility/AccessibilityNodeView.ts +9 -9
  42. package/front_end/panels/accessibility/AccessibilitySubPane.ts +6 -4
  43. package/front_end/panels/accessibility/accessibilityProperties.css +2 -0
  44. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +16 -2
  45. package/front_end/panels/ai_assistance/components/ChatView.ts +9 -10
  46. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +42 -0
  47. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +32 -9
  48. package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +7 -1
  49. package/front_end/panels/common/BadgeNotification.ts +67 -15
  50. package/front_end/panels/common/GdpSignUpDialog.ts +18 -9
  51. package/front_end/panels/console/ConsolePrompt.ts +1 -1
  52. package/front_end/panels/console/ConsoleView.ts +6 -2
  53. package/front_end/panels/elements/ComputedStyleWidget.ts +1 -2
  54. package/front_end/panels/elements/ElementsPanel.ts +4 -0
  55. package/front_end/panels/elements/ElementsTreeElement.ts +18 -0
  56. package/front_end/panels/elements/ElementsTreeOutline.ts +13 -0
  57. package/front_end/panels/elements/LayoutPane.ts +1 -1
  58. package/front_end/panels/elements/StylePropertyTreeElement.ts +21 -6
  59. package/front_end/panels/media/TickingFlameChart.ts +1 -1
  60. package/front_end/panels/network/NetworkLogView.ts +5 -1
  61. package/front_end/panels/profiler/HeapSnapshotView.ts +34 -19
  62. package/front_end/panels/search/SearchResultsPane.ts +126 -145
  63. package/front_end/panels/search/SearchView.ts +43 -59
  64. package/front_end/panels/settings/components/SyncSection.ts +16 -8
  65. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +6 -1
  66. package/front_end/panels/sources/OutlineQuickOpen.ts +3 -1
  67. package/front_end/panels/sources/SourcesPanel.ts +3 -0
  68. package/front_end/panels/timeline/AppenderUtils.ts +2 -2
  69. package/front_end/panels/timeline/ExtensionTrackAppender.ts +13 -4
  70. package/front_end/panels/timeline/GPUTrackAppender.ts +2 -1
  71. package/front_end/panels/timeline/InteractionsTrackAppender.ts +5 -1
  72. package/front_end/panels/timeline/LayoutShiftsTrackAppender.ts +2 -1
  73. package/front_end/panels/timeline/ThreadAppender.ts +12 -3
  74. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +9 -4
  75. package/front_end/panels/timeline/TimelinePanel.ts +3 -2
  76. package/front_end/panels/timeline/TimelineUIUtils.ts +18 -12
  77. package/front_end/panels/timeline/TimingsTrackAppender.ts +6 -1
  78. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +95 -82
  79. package/front_end/panels/timeline/components/LiveMetricsView.ts +2 -2
  80. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +17 -15
  81. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +3 -0
  82. package/front_end/third_party/chromium/README.chromium +1 -1
  83. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  84. package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
  85. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +6 -9
  86. package/front_end/third_party/codemirror.next/package.json +2 -1
  87. package/front_end/third_party/diff/README.chromium +1 -0
  88. package/front_end/third_party/puppeteer/README.chromium +2 -2
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js +0 -20
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Accessibility.js.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  99. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +2 -23
  100. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js +0 -20
  101. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Accessibility.js.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
  103. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
  107. package/front_end/third_party/puppeteer/package/package.json +1 -1
  108. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +1 -21
  109. package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
  110. package/front_end/third_party/puppeteer/package/src/revisions.ts +1 -1
  111. package/front_end/ui/components/text_editor/config.ts +36 -8
  112. package/front_end/ui/components/tooltips/Tooltip.ts +71 -34
  113. package/front_end/ui/legacy/README.md +33 -24
  114. package/front_end/ui/legacy/SearchableView.ts +19 -26
  115. package/front_end/ui/legacy/TextPrompt.ts +166 -1
  116. package/front_end/ui/legacy/Treeoutline.ts +16 -2
  117. package/front_end/ui/legacy/UIUtils.ts +15 -2
  118. package/front_end/ui/legacy/XElement.ts +0 -43
  119. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +20 -4
  120. package/front_end/ui/visual_logging/KnownContextValues.ts +24 -6
  121. package/front_end/ui/visual_logging/README.md +43 -27
  122. package/package.json +1 -1
@@ -106,15 +106,16 @@ const UIStrings = {
106
106
  } as const;
107
107
  const str_ = i18n.i18n.registerUIStrings('panels/search/SearchView.ts', UIStrings);
108
108
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
109
- const {ref} = Directives;
109
+ const {ref, live} = Directives;
110
+ const {widgetConfig} = UI.Widget;
110
111
 
111
112
  interface SearchViewInput {
112
113
  query: string;
113
- focusSearchInput: boolean;
114
114
  matchCase: boolean;
115
115
  isRegex: boolean;
116
116
  searchMessage: string;
117
117
  searchResultsMessage: string;
118
+ searchResultsPane: SearchResultsPane|null;
118
119
  progress: Common.Progress.Progress|null;
119
120
  onQueryChange: (query: string) => void;
120
121
  onQueryKeyDown: (evt: KeyboardEvent) => void;
@@ -127,7 +128,7 @@ interface SearchViewInput {
127
128
  }
128
129
 
129
130
  interface SearchViewOutput {
130
- searchResultsElement?: HTMLElement;
131
+ focusSearchInput: () => void;
131
132
  }
132
133
 
133
134
  type View = (input: SearchViewInput, output: SearchViewOutput, target: HTMLElement) => void;
@@ -135,10 +136,10 @@ type View = (input: SearchViewInput, output: SearchViewOutput, target: HTMLEleme
135
136
  export const DEFAULT_VIEW: View = (input, output, target) => {
136
137
  const {
137
138
  query,
138
- focusSearchInput,
139
139
  matchCase,
140
140
  isRegex,
141
141
  searchMessage,
142
+ searchResultsPane,
142
143
  searchResultsMessage,
143
144
  progress,
144
145
  onQueryChange,
@@ -150,6 +151,18 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
150
151
  onRefresh,
151
152
  onClearSearch,
152
153
  } = input;
154
+ let header = '', text = '';
155
+ if (!query) {
156
+ header = i18nString(UIStrings.noSearchResult);
157
+ text = i18nString(
158
+ UIStrings.typeAndPressSToSearch,
159
+ {PH1: UI.KeyboardShortcut.KeyboardShortcut.shortcutToString(UI.KeyboardShortcut.Keys.Enter)});
160
+ } else if (progress) {
161
+ header = i18nString(UIStrings.searching);
162
+ } else if (!searchResultsPane) {
163
+ header = i18nString(UIStrings.noMatchesFound);
164
+ text = i18nString(UIStrings.nothingMatchedTheQuery);
165
+ }
153
166
  // clang-format off
154
167
  render(html`
155
168
  <style>${searchViewStyles}</style>
@@ -164,14 +177,16 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
164
177
  change: true, keydown: 'ArrowUp|ArrowDown|Enter'})}
165
178
  aria-label=${i18nString(UIStrings.find)}
166
179
  size="100" results="0"
167
- .value=${query}
180
+ .value=${live(query)}
168
181
  @keydown=${onQueryKeyDown}
169
182
  @input=${(e: Event) => onQueryChange((e.target as HTMLInputElement).value)}
170
183
  ${ref(e => {
171
- if (e instanceof HTMLInputElement && focusSearchInput) {
172
- e.focus();
173
- e.select();
174
- }
184
+ output.focusSearchInput = () => {
185
+ if (e instanceof HTMLInputElement) {
186
+ e.focus();
187
+ e.select();
188
+ }
189
+ };
175
190
  })}>
176
191
  <devtools-button class="clear-button" tabindex="-1"
177
192
  @click=${onClearSearchInput}
@@ -224,8 +239,13 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
224
239
  } as Buttons.Button.ButtonData}></devtools-button>
225
240
  </devtools-toolbar>
226
241
  </div>
227
- <div class="search-results" @keydown=${onPanelKeyDown}
228
- ${ref(e => {output.searchResultsElement = e as HTMLElement;})}>
242
+ <div class="search-results" @keydown=${onPanelKeyDown}>
243
+ ${searchResultsPane
244
+ ? html`<devtools-widget .widgetConfig=${widgetConfig(UI.Widget.VBox)}>
245
+ ${searchResultsPane.element}
246
+ </devtools-widget>`
247
+ : html`<devtools-widget .widgetConfig=${widgetConfig(UI.EmptyWidget.EmptyWidget, {header, text})}>
248
+ </devtools-widget>`}
229
249
  </div>
230
250
  <div class="search-toolbar-summary" @keydown=${onPanelKeyDown}>
231
251
  <div class="search-message">${searchMessage}</div>
@@ -242,20 +262,17 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
242
262
 
243
263
  export class SearchView extends UI.Widget.VBox {
244
264
  readonly #view: View;
245
- #focusSearchInput: boolean;
265
+ #focusSearchInput = (): void => {};
246
266
  #isIndexing: boolean;
247
267
  #searchId: number;
248
268
  #searchMatchesCount: number;
249
269
  #searchResultsCount: number;
250
270
  #nonEmptySearchResultsCount: number;
251
271
  #searchingView: UI.Widget.Widget|null;
252
- #notFoundView: UI.Widget.Widget|null;
253
272
  #searchConfig: Workspace.SearchConfig.SearchConfig|null;
254
273
  #pendingSearchConfig: Workspace.SearchConfig.SearchConfig|null;
255
274
  #searchResultsPane: SearchResultsPane|null;
256
275
  #progress: Common.Progress.Progress|null;
257
- #visiblePane: UI.Widget.Widget|null;
258
- #searchResultsElement!: HTMLElement;
259
276
  #query: string;
260
277
  #matchCase = false;
261
278
  #isRegex = false;
@@ -272,7 +289,6 @@ export class SearchView extends UI.Widget.VBox {
272
289
  // result added.
273
290
  #throttler: Common.Throttler.Throttler;
274
291
  #pendingSearchResults: SearchResult[] = [];
275
- #emptyStartView: UI.EmptyWidget.EmptyWidget;
276
292
 
277
293
  constructor(settingKey: string, throttler: Common.Throttler.Throttler, view = DEFAULT_VIEW) {
278
294
  super({
@@ -282,7 +298,6 @@ export class SearchView extends UI.Widget.VBox {
282
298
  this.#view = view;
283
299
  this.setMinimumSize(0, 40);
284
300
 
285
- this.#focusSearchInput = false;
286
301
  this.#isIndexing = false;
287
302
  this.#searchId = 1;
288
303
  this.#query = '';
@@ -290,12 +305,10 @@ export class SearchView extends UI.Widget.VBox {
290
305
  this.#searchResultsCount = 0;
291
306
  this.#nonEmptySearchResultsCount = 0;
292
307
  this.#searchingView = null;
293
- this.#notFoundView = null;
294
308
  this.#searchConfig = null;
295
309
  this.#pendingSearchConfig = null;
296
310
  this.#searchResultsPane = null;
297
311
  this.#progress = null;
298
- this.#visiblePane = null;
299
312
  this.#throttler = throttler;
300
313
 
301
314
  this.#advancedSearchConfig = Common.Settings.Settings.instance().createLocalSetting(
@@ -305,21 +318,15 @@ export class SearchView extends UI.Widget.VBox {
305
318
  this.#load();
306
319
  this.performUpdate();
307
320
  this.#searchScope = null;
308
-
309
- this.#emptyStartView = new UI.EmptyWidget.EmptyWidget(
310
- i18nString(UIStrings.noSearchResult), i18nString(UIStrings.typeAndPressSToSearch, {
311
- PH1: UI.KeyboardShortcut.KeyboardShortcut.shortcutToString(UI.KeyboardShortcut.Keys.Enter)
312
- }));
313
- this.#showPane(this.#emptyStartView);
314
321
  }
315
322
 
316
323
  override performUpdate(): void {
317
324
  const input: SearchViewInput = {
318
325
  query: this.#query,
319
- focusSearchInput: this.#focusSearchInput,
320
326
  matchCase: this.#matchCase,
321
327
  isRegex: this.#isRegex,
322
328
  searchMessage: this.#searchMessage,
329
+ searchResultsPane: this.#searchResultsPane,
323
330
  searchResultsMessage: this.#searchResultsMessage,
324
331
  progress: this.#progress,
325
332
  onQueryChange: (query: string) => {
@@ -333,12 +340,13 @@ export class SearchView extends UI.Widget.VBox {
333
340
  onRefresh: this.#onRefresh.bind(this),
334
341
  onClearSearch: this.#onClearSearch.bind(this),
335
342
  };
336
- const output: SearchViewOutput = {};
343
+ const that = this;
344
+ const output: SearchViewOutput = {
345
+ set focusSearchInput(value: () => void) {
346
+ that.#focusSearchInput = value;
347
+ }
348
+ };
337
349
  this.#view(input, output, this.contentElement);
338
- this.#focusSearchInput = false;
339
- if (output.searchResultsElement) {
340
- this.#searchResultsElement = output.searchResultsElement;
341
- }
342
350
  }
343
351
 
344
352
  #onToggleRegex(): void {
@@ -358,7 +366,9 @@ export class SearchView extends UI.Widget.VBox {
358
366
  toggle(queryCandidate: string, searchImmediately?: boolean): void {
359
367
  this.#query = queryCandidate;
360
368
  this.requestUpdate();
361
- this.focus();
369
+ void this.updateComplete.then(() => {
370
+ this.focus();
371
+ });
362
372
 
363
373
  this.#initScope();
364
374
  if (searchImmediately) {
@@ -416,7 +426,6 @@ export class SearchView extends UI.Widget.VBox {
416
426
  this.requestUpdate();
417
427
  this.#save();
418
428
  this.focus();
419
- this.#showPane(this.#emptyStartView);
420
429
  }
421
430
 
422
431
  #onSearchResult(searchId: number, searchResult: SearchResult): void {
@@ -429,7 +438,6 @@ export class SearchView extends UI.Widget.VBox {
429
438
  }
430
439
  if (!this.#searchResultsPane) {
431
440
  this.#searchResultsPane = this.createSearchResultsPane();
432
- this.#showPane(this.#searchResultsPane);
433
441
  }
434
442
  this.#pendingSearchResults.push(searchResult);
435
443
  void this.#throttler.schedule(async () => this.#addPendingSearchResults());
@@ -453,9 +461,6 @@ export class SearchView extends UI.Widget.VBox {
453
461
  if (searchId !== this.#searchId || !this.#progress) {
454
462
  return;
455
463
  }
456
- if (!this.#searchResultsPane) {
457
- this.#nothingFound();
458
- }
459
464
  this.#progress = null;
460
465
  this.#searchFinished(finished);
461
466
  this.#searchConfig = null;
@@ -479,7 +484,6 @@ export class SearchView extends UI.Widget.VBox {
479
484
 
480
485
  #resetSearch(): void {
481
486
  this.#stopSearch();
482
- this.#showPane(null);
483
487
  this.#searchResultsPane = null;
484
488
  this.#searchMessage = '';
485
489
  this.#searchResultsMessage = '';
@@ -503,7 +507,6 @@ export class SearchView extends UI.Widget.VBox {
503
507
  if (!this.#searchingView) {
504
508
  this.#searchingView = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.searching), '');
505
509
  }
506
- this.#showPane(this.#searchingView);
507
510
  this.#searchMessage = i18nString(UIStrings.searching);
508
511
  this.performUpdate();
509
512
  this.#updateSearchResultsMessage();
@@ -526,24 +529,6 @@ export class SearchView extends UI.Widget.VBox {
526
529
  this.performUpdate();
527
530
  }
528
531
 
529
- #showPane(panel: UI.Widget.Widget|null): void {
530
- if (this.#visiblePane) {
531
- this.#visiblePane.detach();
532
- }
533
- if (panel) {
534
- panel.show(this.#searchResultsElement);
535
- }
536
- this.#visiblePane = panel;
537
- }
538
-
539
- #nothingFound(): void {
540
- if (!this.#notFoundView) {
541
- this.#notFoundView = new UI.EmptyWidget.EmptyWidget(
542
- i18nString(UIStrings.noMatchesFound), i18nString(UIStrings.nothingMatchedTheQuery));
543
- }
544
- this.#showPane(this.#notFoundView);
545
- }
546
-
547
532
  #addSearchResult(searchResult: SearchResult): void {
548
533
  const matchesCount = searchResult.matchesCount();
549
534
  this.#searchMatchesCount += matchesCount;
@@ -560,8 +545,7 @@ export class SearchView extends UI.Widget.VBox {
560
545
  }
561
546
 
562
547
  override focus(): void {
563
- this.#focusSearchInput = true;
564
- this.requestUpdate();
548
+ this.#focusSearchInput();
565
549
  }
566
550
 
567
551
  override willHide(): void {
@@ -17,6 +17,7 @@ import * as Buttons from '../../../ui/components/buttons/buttons.js';
17
17
  import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
18
18
  import type * as SettingsComponents from '../../../ui/components/settings/settings.js';
19
19
  import * as Lit from '../../../ui/lit/lit.js';
20
+ import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
20
21
  import * as PanelCommon from '../../common/common.js';
21
22
  import * as PanelUtils from '../../utils/utils.js';
22
23
 
@@ -212,7 +213,7 @@ export class SyncSection extends HTMLElement {
212
213
  }
213
214
 
214
215
  async #fetchGdpDetails(): Promise<void> {
215
- if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled) {
216
+ if (!Host.GdpClient.isGdpProfilesAvailable()) {
216
217
  return;
217
218
  }
218
219
 
@@ -304,21 +305,25 @@ function renderGdpSectionIfNeeded({
304
305
  gdpProfile?: Host.GdpClient.Profile,
305
306
  isEligibleToCreateProfile?: boolean,
306
307
  }): Lit.LitTemplate {
307
- // clang-format off
308
- if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled || (!gdpProfile && !isEligibleToCreateProfile)) {
308
+ if (!Host.GdpClient.isGdpProfilesAvailable() || (!gdpProfile && !isEligibleToCreateProfile)) {
309
309
  return Lit.nothing;
310
310
  }
311
+ const hasReceiveBadgesCheckbox = receiveBadgesSetting &&
312
+ Host.GdpClient.getGdpProfilesEnterprisePolicy() === Root.Runtime.GdpProfilesEnterprisePolicyValue.ENABLED;
311
313
 
312
314
  function renderBrand(): Lit.LitTemplate {
315
+ // clang-format off
313
316
  return html`
314
317
  <div class="gdp-profile-header">
315
318
  <div class="gdp-logo" role="img" tabindex="0" aria-label="Google Developer Program"></div>
316
319
  </div>
317
320
  `;
321
+ // clang-format on
318
322
  }
319
323
 
324
+ // clang-format off
320
325
  return html`
321
- <div class="gdp-profile-container">
326
+ <div class="gdp-profile-container" jslog=${VisualLogging.section().context('gdp-profile')}>
322
327
  <div class="divider"></div>
323
328
  ${gdpProfile ? html`
324
329
  <div class="gdp-profile-details-content">
@@ -326,10 +331,13 @@ function renderGdpSectionIfNeeded({
326
331
  <div class="plan-details">
327
332
  ${getGdpSubscriptionText(gdpProfile)}
328
333
  &nbsp;·&nbsp;
329
- <x-link class="link" href=${Host.GdpClient.GOOGLE_DEVELOPER_PROGRAM_PROFILE_LINK}>
334
+ <x-link
335
+ jslog=${VisualLogging.link().track({click: true, keydown:'Enter|Space'}).context('view-profile')}
336
+ class="link"
337
+ href=${Host.GdpClient.GOOGLE_DEVELOPER_PROGRAM_PROFILE_LINK}>
330
338
  ${i18nString(UIStrings.viewProfile)}
331
339
  </x-link></div>
332
- ${receiveBadgesSetting ? html`
340
+ ${hasReceiveBadgesCheckbox ? html`
333
341
  <div class="setting-container" ${ref(receiveBadgesSettingContainerRef)}>
334
342
  <setting-checkbox class="setting-checkbox" .data=${{setting: receiveBadgesSetting}} @change=${(e: Event) => {
335
343
  const settingCheckbox = e.target as SettingsComponents.SettingCheckbox.SettingCheckbox;
@@ -351,7 +359,7 @@ function renderGdpSectionIfNeeded({
351
359
  @click=${() => PanelCommon.GdpSignUpDialog.show({
352
360
  onSuccess: onSignUpSuccess
353
361
  })}
354
- .jslogContext=${'gdp.sign-up-dialog-open'}
362
+ .jslogContext=${'open-sign-up-dialog'}
355
363
  .variant=${Buttons.Button.Variant.OUTLINED}>
356
364
  ${i18nString(UIStrings.signUp)}
357
365
  </devtools-button>
@@ -359,8 +367,8 @@ function renderGdpSectionIfNeeded({
359
367
  `}
360
368
  </div>
361
369
  `;
370
+ // clang-format on
362
371
  }
363
- // clang-format on
364
372
 
365
373
  customElements.define('devtools-sync-section', SyncSection);
366
374
 
@@ -18,6 +18,7 @@ import {Plugin} from './Plugin.js';
18
18
 
19
19
  const AI_CODE_COMPLETION_CHARACTER_LIMIT = 20_000;
20
20
  const DISCLAIMER_TOOLTIP_ID = 'sources-ai-code-completion-disclaimer-tooltip';
21
+ const SPINNER_TOOLTIP_ID = 'sources-ai-code-completion-spinner-tooltip';
21
22
  const CITATIONS_TOOLTIP_ID = 'sources-ai-code-completion-citations-tooltip';
22
23
 
23
24
  export class AiCodeCompletionPlugin extends Plugin {
@@ -212,8 +213,11 @@ export class AiCodeCompletionPlugin extends Plugin {
212
213
  this.#teaser = undefined;
213
214
  }
214
215
  if (!this.#aiCodeCompletion) {
216
+ const contextFlavor = this.uiSourceCode.url().startsWith('snippet://') ?
217
+ AiCodeCompletion.AiCodeCompletion.ContextFlavor.CONSOLE :
218
+ AiCodeCompletion.AiCodeCompletion.ContextFlavor.SOURCES;
215
219
  this.#aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
216
- {aidaClient: this.#aidaClient}, this.#editor, AiCodeCompletion.AiCodeCompletion.Panel.SOURCES);
220
+ {aidaClient: this.#aidaClient}, this.#editor, contextFlavor);
217
221
  this.#aiCodeCompletion.addEventListener(
218
222
  AiCodeCompletion.AiCodeCompletion.Events.REQUEST_TRIGGERED, this.#onAiRequestTriggered, this);
219
223
  this.#aiCodeCompletion.addEventListener(
@@ -229,6 +233,7 @@ export class AiCodeCompletionPlugin extends Plugin {
229
233
  }
230
234
  this.#aiCodeCompletionDisclaimer = new PanelCommon.AiCodeCompletionDisclaimer();
231
235
  this.#aiCodeCompletionDisclaimer.disclaimerTooltipId = DISCLAIMER_TOOLTIP_ID;
236
+ this.#aiCodeCompletionDisclaimer.spinnerTooltipId = SPINNER_TOOLTIP_ID;
232
237
  this.#aiCodeCompletionDisclaimer.show(this.#aiCodeCompletionDisclaimerContainer, undefined, true);
233
238
  }
234
239
 
@@ -44,7 +44,9 @@ export function outline(state: CodeMirror.EditorState): OutlineItem[] {
44
44
 
45
45
  function subtitleFromParamList(): string {
46
46
  while (cursor.name !== 'ParamList') {
47
- cursor.nextSibling();
47
+ if (!cursor.nextSibling()) {
48
+ break;
49
+ }
48
50
  }
49
51
  let parameters = '';
50
52
  if (cursor.name === 'ParamList' && cursor.firstChild()) {
@@ -38,6 +38,7 @@ import * as Platform from '../../core/platform/platform.js';
38
38
  import * as Root from '../../core/root/root.js';
39
39
  import * as SDK from '../../core/sdk/sdk.js';
40
40
  import * as Protocol from '../../generated/protocol.js';
41
+ import * as Badges from '../../models/badges/badges.js';
41
42
  import * as Bindings from '../../models/bindings/bindings.js';
42
43
  import * as Breakpoints from '../../models/breakpoints/breakpoints.js';
43
44
  import * as Extensions from '../../models/extensions/extensions.js';
@@ -484,6 +485,8 @@ export class SourcesPanel extends UI.Panel.Panel implements
484
485
  } else if (!this.#paused) {
485
486
  UI.Context.Context.instance().setFlavor(SDK.Target.Target, debuggerModel.target());
486
487
  }
488
+
489
+ Badges.UserBadges.instance().recordAction(Badges.BadgeAction.DEBUGGER_PAUSED);
487
490
  }
488
491
 
489
492
  private debugInfoAttached(event: Common.EventTarget.EventTargetEvent<SDK.Script.Script>): void {
@@ -4,7 +4,7 @@
4
4
  import type * as Common from '../../core/common/common.js';
5
5
  import * as i18n from '../../core/i18n/i18n.js';
6
6
  import * as Trace from '../../models/trace/trace.js';
7
- import type * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
7
+ import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
8
8
  import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
9
9
 
10
10
  import type {VisualLoggingTrackName} from './CompatibilityTracksAppender.js';
@@ -36,7 +36,7 @@ export function buildGroupStyle(extra?: Partial<PerfUI.FlameChart.GroupStyle>):
36
36
  const defaultGroupStyle: PerfUI.FlameChart.GroupStyle = {
37
37
  padding: 4,
38
38
  height: 17,
39
- collapsible: true,
39
+ collapsible: PerfUI.FlameChart.GroupCollapsibleState.ALWAYS,
40
40
  color: ThemeSupport.ThemeSupport.instance().getComputedValue('--sys-color-on-surface'),
41
41
  backgroundColor: ThemeSupport.ThemeSupport.instance().getComputedValue('--sys-color-cdt-base-container'),
42
42
  nestingLevel: 0,
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
  import * as i18n from '../../core/i18n/i18n.js';
5
5
  import * as Trace from '../../models/trace/trace.js';
6
+ import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
6
7
  import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
7
8
 
8
9
  import {buildGroupStyle, buildTrackHeader, getDurationString} from './AppenderUtils.js';
@@ -42,7 +43,8 @@ export class ExtensionTrackAppender implements TrackAppender {
42
43
  if (totalEntryCount === 0) {
43
44
  return trackStartLevel;
44
45
  }
45
- this.#appendTopLevelHeaderAtLevel(trackStartLevel, expanded);
46
+ const compact = !this.#extensionTopLevelTrack.isTrackGroup && totalEntryCount < 2;
47
+ this.#appendTopLevelHeaderAtLevel(trackStartLevel, compact, expanded);
46
48
  return this.#appendExtensionTrackData(trackStartLevel);
47
49
  }
48
50
 
@@ -52,8 +54,10 @@ export class ExtensionTrackAppender implements TrackAppender {
52
54
  * header corresponds to the track name, in the latter it corresponds
53
55
  * to the track group name.
54
56
  */
55
- #appendTopLevelHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
56
- const style = buildGroupStyle({shareHeaderLine: false, collapsible: true});
57
+ #appendTopLevelHeaderAtLevel(currentLevel: number, compact: boolean, expanded?: boolean): void {
58
+ const style = compact ?
59
+ buildGroupStyle({shareHeaderLine: true, collapsible: PerfUI.FlameChart.GroupCollapsibleState.NEVER}) :
60
+ buildGroupStyle({shareHeaderLine: false, collapsible: PerfUI.FlameChart.GroupCollapsibleState.ALWAYS});
57
61
  const headerTitle = this.#extensionTopLevelTrack.name;
58
62
  const jsLogContext = this.#extensionTopLevelTrack.name === '🅰️ Angular' ? VisualLoggingTrackName.ANGULAR_TRACK :
59
63
  VisualLoggingTrackName.EXTENSION;
@@ -69,7 +73,12 @@ export class ExtensionTrackAppender implements TrackAppender {
69
73
  * corresponds to the track name itself, instead of the track name.
70
74
  */
71
75
  #appendSecondLevelHeader(trackStartLevel: number, headerTitle: string): void {
72
- const style = buildGroupStyle({shareHeaderLine: false, padding: 2, nestingLevel: 1, collapsible: true});
76
+ const style = buildGroupStyle({
77
+ shareHeaderLine: false,
78
+ padding: 2,
79
+ nestingLevel: 1,
80
+ collapsible: PerfUI.FlameChart.GroupCollapsibleState.ALWAYS
81
+ });
73
82
  const group = buildTrackHeader(
74
83
  VisualLoggingTrackName.EXTENSION, trackStartLevel, headerTitle, style,
75
84
  /* selectable= */ true);
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
  import * as i18n from '../../core/i18n/i18n.js';
5
5
  import * as Trace from '../../models/trace/trace.js';
6
+ import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
6
7
  import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
7
8
 
8
9
  import {buildGroupStyle, buildTrackHeader} from './AppenderUtils.js';
@@ -63,7 +64,7 @@ export class GPUTrackAppender implements TrackAppender {
63
64
  * @param expanded whether the track should be rendered expanded.
64
65
  */
65
66
  #appendTrackHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
66
- const style = buildGroupStyle({collapsible: false});
67
+ const style = buildGroupStyle({collapsible: PerfUI.FlameChart.GroupCollapsibleState.NEVER});
67
68
  const group = buildTrackHeader(
68
69
  VisualLoggingTrackName.GPU, currentLevel, i18nString(UIStrings.gpu), style, /* selectable= */ true, expanded);
69
70
  this.#compatibilityBuilder.registerTrackForGroup(group, this);
@@ -69,7 +69,11 @@ export class InteractionsTrackAppender implements TrackAppender {
69
69
  */
70
70
  #appendTrackHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
71
71
  const trackIsCollapsible = this.#parsedTrace.data.UserInteractions.interactionEvents.length > 0;
72
- const style = buildGroupStyle({collapsible: trackIsCollapsible, useDecoratorsForOverview: true});
72
+ const style = buildGroupStyle({
73
+ collapsible: trackIsCollapsible ? PerfUI.FlameChart.GroupCollapsibleState.ALWAYS :
74
+ PerfUI.FlameChart.GroupCollapsibleState.NEVER,
75
+ useDecoratorsForOverview: true,
76
+ });
73
77
  const group = buildTrackHeader(
74
78
  VisualLoggingTrackName.INTERACTIONS, currentLevel, i18nString(UIStrings.interactions), style,
75
79
  /* selectable= */ true, expanded);
@@ -8,6 +8,7 @@ import * as i18n from '../../core/i18n/i18n.js';
8
8
  import * as Geometry from '../../models/geometry/geometry.js';
9
9
  import * as Trace from '../../models/trace/trace.js';
10
10
  import * as ComponentHelpers from '../../ui/components/helpers/helpers.js';
11
+ import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
11
12
  import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
12
13
 
13
14
  import {buildGroupStyle, buildTrackHeader} from './AppenderUtils.js';
@@ -85,7 +86,7 @@ export class LayoutShiftsTrackAppender implements TrackAppender {
85
86
  * appended.
86
87
  */
87
88
  #appendTrackHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
88
- const style = buildGroupStyle({collapsible: false});
89
+ const style = buildGroupStyle({collapsible: PerfUI.FlameChart.GroupCollapsibleState.NEVER});
89
90
  const group = buildTrackHeader(
90
91
  VisualLoggingTrackName.LAYOUT_SHIFTS, currentLevel, i18nString(UIStrings.layoutShifts), style,
91
92
  /* selectable= */ true, expanded);
@@ -262,7 +262,11 @@ export class ThreadAppender implements TrackAppender {
262
262
  */
263
263
  #appendTrackHeaderAtLevel(currentLevel: number): void {
264
264
  const trackIsCollapsible = this.#entries.length > 0;
265
- const style = buildGroupStyle({shareHeaderLine: false, collapsible: trackIsCollapsible});
265
+ const style = buildGroupStyle({
266
+ shareHeaderLine: false,
267
+ collapsible: trackIsCollapsible ? PerfUI.FlameChart.GroupCollapsibleState.ALWAYS :
268
+ PerfUI.FlameChart.GroupCollapsibleState.NEVER,
269
+ });
266
270
  if (this.#headerNestingLevel !== null) {
267
271
  style.nestingLevel = this.#headerNestingLevel;
268
272
  }
@@ -304,7 +308,11 @@ export class ThreadAppender implements TrackAppender {
304
308
  const currentTrackCount = this.#compatibilityBuilder.getCurrentTrackCountForThreadType(threadType);
305
309
  if (currentTrackCount === 0) {
306
310
  const trackIsCollapsible = this.#entries.length > 0;
307
- const headerStyle = buildGroupStyle({shareHeaderLine: false, collapsible: trackIsCollapsible});
311
+ const headerStyle = buildGroupStyle({
312
+ shareHeaderLine: false,
313
+ collapsible: trackIsCollapsible ? PerfUI.FlameChart.GroupCollapsibleState.ALWAYS :
314
+ PerfUI.FlameChart.GroupCollapsibleState.NEVER,
315
+ });
308
316
 
309
317
  // Don't set any jslogcontext (first argument) because this is a shared
310
318
  // header group. Each child will have its context set.
@@ -315,7 +323,8 @@ export class ThreadAppender implements TrackAppender {
315
323
 
316
324
  // Nesting is set to 1 because the track is appended inside the
317
325
  // header for all raster threads.
318
- const titleStyle = buildGroupStyle({padding: 2, nestingLevel: 1, collapsible: false});
326
+ const titleStyle =
327
+ buildGroupStyle({padding: 2, nestingLevel: 1, collapsible: PerfUI.FlameChart.GroupCollapsibleState.NEVER});
319
328
  const rasterizerTitle = this.threadType === Trace.Handlers.Threads.ThreadType.RASTERIZER ?
320
329
  i18nString(UIStrings.rasterizerThreadS, {PH1: currentTrackCount + 1}) :
321
330
  i18nString(UIStrings.threadPoolThreadS, {PH1: currentTrackCount + 1});
@@ -152,8 +152,12 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
152
152
  [this.droppedFramePattern, this.partialFramePattern] = this.preparePatternCanvas();
153
153
 
154
154
  this.framesGroupStyle = this.buildGroupStyle({useFirstLineForOverview: true});
155
- this.screenshotsGroupStyle =
156
- this.buildGroupStyle({useFirstLineForOverview: true, nestingLevel: 1, collapsible: false, itemsHeight: 150});
155
+ this.screenshotsGroupStyle = this.buildGroupStyle({
156
+ useFirstLineForOverview: true,
157
+ nestingLevel: 1,
158
+ collapsible: PerfUI.FlameChart.GroupCollapsibleState.NEVER,
159
+ itemsHeight: 150
160
+ });
157
161
 
158
162
  ThemeSupport.ThemeSupport.instance().addEventListener(ThemeSupport.ThemeChangeEvent.eventName, () => {
159
163
  const headers = [
@@ -427,7 +431,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
427
431
  const defaultGroupStyle = {
428
432
  padding: 4,
429
433
  height: 17,
430
- collapsible: true,
434
+ collapsible: PerfUI.FlameChart.GroupCollapsibleState.ALWAYS,
431
435
  color: ThemeSupport.ThemeSupport.instance().getComputedValue('--sys-color-on-surface'),
432
436
  backgroundColor: ThemeSupport.ThemeSupport.instance().getComputedValue('--sys-color-cdt-base-container'),
433
437
  nestingLevel: 0,
@@ -774,7 +778,8 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
774
778
  return;
775
779
  }
776
780
 
777
- this.framesGroupStyle.collapsible = hasScreenshots;
781
+ this.framesGroupStyle.collapsible =
782
+ hasScreenshots ? PerfUI.FlameChart.GroupCollapsibleState.ALWAYS : PerfUI.FlameChart.GroupCollapsibleState.NEVER;
778
783
  const expanded = Root.Runtime.Runtime.queryParam('flamechart-force-expand') === 'frames';
779
784
 
780
785
  this.appendHeader(i18nString(UIStrings.frames), this.framesGroupStyle, false /* selectable */, expanded);
@@ -2242,7 +2242,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2242
2242
  }
2243
2243
 
2244
2244
  UI.Context.Context.instance().setFlavor(
2245
- AiAssistanceModel.AgentFocus, AiAssistanceModel.AgentFocus.full(parsedTrace));
2245
+ AiAssistanceModel.AgentFocus, AiAssistanceModel.AgentFocus.fromParsedTrace(parsedTrace));
2246
2246
  }
2247
2247
 
2248
2248
  #onAnnotationModifiedEvent(e: Event): void {
@@ -3079,7 +3079,8 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
3079
3079
  for (const modelName in insightsForNav.model) {
3080
3080
  const model = modelName as keyof Trace.Insights.Types.InsightModelsType;
3081
3081
  const insight = insightsForNav.model[model];
3082
- const formatter = new AiAssistanceModel.PerformanceInsightFormatter(parsedTrace, insight);
3082
+ const focus = AiAssistanceModel.AgentFocus.fromParsedTrace(parsedTrace);
3083
+ const formatter = new AiAssistanceModel.PerformanceInsightFormatter(focus, insight);
3083
3084
  if (!formatter.insightIsSupported()) {
3084
3085
  // Not all Insights are integrated with "Ask AI" yet, let's avoid
3085
3086
  // filling up the response with those ones because there will be no