chrome-devtools-frontend 1.0.1516909 → 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 (94) 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 +4 -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 +166 -49
  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 +17 -11
  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 +21 -3
  34. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  35. package/front_end/models/trace/README.md +28 -1
  36. package/front_end/models/trace/handlers/UserTimingsHandler.ts +1 -1
  37. package/front_end/models/trace/helpers/Trace.ts +99 -43
  38. package/front_end/models/trace/types/TraceEvents.ts +9 -0
  39. package/front_end/panels/accessibility/ARIAAttributesView.ts +113 -191
  40. package/front_end/panels/accessibility/AccessibilityNodeView.ts +9 -9
  41. package/front_end/panels/accessibility/AccessibilitySubPane.ts +6 -4
  42. package/front_end/panels/accessibility/accessibilityProperties.css +2 -0
  43. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +16 -2
  44. package/front_end/panels/ai_assistance/components/ChatView.ts +9 -10
  45. package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +42 -0
  46. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +32 -9
  47. package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +7 -1
  48. package/front_end/panels/common/BadgeNotification.ts +21 -5
  49. package/front_end/panels/common/GdpSignUpDialog.ts +18 -9
  50. package/front_end/panels/console/ConsolePrompt.ts +1 -1
  51. package/front_end/panels/console/ConsoleView.ts +6 -2
  52. package/front_end/panels/elements/ElementsPanel.ts +4 -0
  53. package/front_end/panels/elements/ElementsTreeElement.ts +18 -0
  54. package/front_end/panels/elements/ElementsTreeOutline.ts +13 -0
  55. package/front_end/panels/elements/StylePropertyTreeElement.ts +21 -6
  56. package/front_end/panels/media/TickingFlameChart.ts +1 -1
  57. package/front_end/panels/profiler/HeapSnapshotView.ts +34 -19
  58. package/front_end/panels/search/SearchResultsPane.ts +124 -128
  59. package/front_end/panels/search/SearchView.ts +24 -17
  60. package/front_end/panels/settings/components/SyncSection.ts +16 -8
  61. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +6 -1
  62. package/front_end/panels/sources/SourcesPanel.ts +3 -0
  63. package/front_end/panels/timeline/AppenderUtils.ts +2 -2
  64. package/front_end/panels/timeline/ExtensionTrackAppender.ts +13 -4
  65. package/front_end/panels/timeline/GPUTrackAppender.ts +2 -1
  66. package/front_end/panels/timeline/InteractionsTrackAppender.ts +5 -1
  67. package/front_end/panels/timeline/LayoutShiftsTrackAppender.ts +2 -1
  68. package/front_end/panels/timeline/ThreadAppender.ts +12 -3
  69. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +9 -4
  70. package/front_end/panels/timeline/TimelinePanel.ts +3 -2
  71. package/front_end/panels/timeline/TimelineUIUtils.ts +5 -4
  72. package/front_end/panels/timeline/TimingsTrackAppender.ts +6 -1
  73. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +95 -82
  74. package/front_end/panels/timeline/components/LiveMetricsView.ts +2 -2
  75. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +17 -15
  76. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +3 -0
  77. package/front_end/third_party/chromium/README.chromium +1 -1
  78. package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
  79. package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
  80. package/front_end/third_party/codemirror.next/codemirror.next.d.ts +6 -9
  81. package/front_end/third_party/codemirror.next/package.json +2 -1
  82. package/front_end/third_party/diff/README.chromium +1 -0
  83. package/front_end/ui/components/text_editor/config.ts +6 -7
  84. package/front_end/ui/components/tooltips/Tooltip.ts +70 -31
  85. package/front_end/ui/legacy/README.md +33 -24
  86. package/front_end/ui/legacy/SearchableView.ts +19 -26
  87. package/front_end/ui/legacy/TextPrompt.ts +166 -1
  88. package/front_end/ui/legacy/Treeoutline.ts +16 -2
  89. package/front_end/ui/legacy/UIUtils.ts +15 -2
  90. package/front_end/ui/legacy/XElement.ts +0 -43
  91. package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +20 -4
  92. package/front_end/ui/visual_logging/KnownContextValues.ts +19 -6
  93. package/front_end/ui/visual_logging/README.md +43 -27
  94. package/package.json +1 -1
@@ -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 || Root.Runtime.hostConfig.isOffTheRecord) {
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
 
@@ -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
@@ -376,9 +376,10 @@ const UIStrings = {
376
376
  compositingFailedUnknownReason: 'Unknown Reason',
377
377
 
378
378
  /**
379
- * @description Text for the execution stack trace
379
+ * @description Text for the execution "stack trace". It is not technically a stack trace, because it points to the beginning of each function
380
+ * and not to each call site, so we call it a function stack instead to avoid confusion.
380
381
  */
381
- stackTrace: 'Stack trace',
382
+ functionStack: 'Function stack',
382
383
  /**
383
384
  * @description Text used to show any invalidations for a particular event that caused the browser to have to do more work to update the page.
384
385
  * @example {2} PH1
@@ -1711,10 +1712,10 @@ export class TimelineUIUtils {
1711
1712
  parsedTrace: Trace.TraceModel.ParsedTrace): Promise<void> {
1712
1713
  const {startTime} = Trace.Helpers.Timing.eventTimingsMilliSeconds(event);
1713
1714
  let initiatorStackLabel = i18nString(UIStrings.initiatorStackTrace);
1714
- let stackLabel = i18nString(UIStrings.stackTrace);
1715
+ let stackLabel = i18nString(UIStrings.functionStack);
1715
1716
  const stackTraceForEvent = Trace.Extras.StackTraceForEvent.get(event, parsedTrace.data);
1716
1717
  if (stackTraceForEvent?.callFrames.length || stackTraceForEvent?.description || stackTraceForEvent?.parent) {
1717
- contentHelper.addSection(i18nString(UIStrings.stackTrace));
1718
+ contentHelper.addSection(i18nString(UIStrings.functionStack));
1718
1719
  contentHelper.createChildStackTraceElement(stackTraceForEvent);
1719
1720
  // TODO(andoli): also build stack trace component for other events
1720
1721
  // that have a stack trace using the StackTraceForEvent helper.
@@ -4,6 +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 * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
7
8
 
8
9
  import {buildGroupStyle, buildTrackHeader, getDurationString} from './AppenderUtils.js';
9
10
  import {
@@ -103,7 +104,11 @@ export class TimingsTrackAppender implements TrackAppender {
103
104
  */
104
105
  #appendTrackHeaderAtLevel(currentLevel: number, expanded?: boolean): void {
105
106
  const trackIsCollapsible = this.#parsedTrace.data.UserTimings.performanceMeasures.length > 0;
106
- const style = buildGroupStyle({useFirstLineForOverview: true, collapsible: trackIsCollapsible});
107
+ const style = buildGroupStyle({
108
+ useFirstLineForOverview: true,
109
+ collapsible: trackIsCollapsible ? PerfUI.FlameChart.GroupCollapsibleState.IF_MULTI_ROW :
110
+ PerfUI.FlameChart.GroupCollapsibleState.NEVER,
111
+ });
107
112
  const group = buildTrackHeader(
108
113
  VisualLoggingTrackName.TIMINGS, currentLevel, i18nString(UIStrings.timings), style, /* selectable= */ true,
109
114
  expanded);
@@ -1,7 +1,6 @@
1
1
  // Copyright 2024 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- /* eslint-disable rulesdir/no-lit-render-outside-of-view */
5
4
 
6
5
  import '../../../ui/components/icon_button/icon_button.js';
7
6
  import '../../../ui/components/menus/menus.js';
@@ -9,15 +8,15 @@ import '../../../ui/components/menus/menus.js';
9
8
  import * as Common from '../../../core/common/common.js';
10
9
  import * as i18n from '../../../core/i18n/i18n.js';
11
10
  import * as SDK from '../../../core/sdk/sdk.js';
12
- import * as ComponentHelpers from '../../../ui/components/helpers/helpers.js';
13
11
  import type * as Menus from '../../../ui/components/menus/menus.js';
12
+ import * as UI from '../../../ui/legacy/legacy.js';
14
13
  import * as Lit from '../../../ui/lit/lit.js';
15
14
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
16
15
  import * as MobileThrottling from '../../mobile_throttling/mobile_throttling.js';
17
16
 
18
17
  import cpuThrottlingSelectorStyles from './cpuThrottlingSelector.css.js';
19
18
 
20
- const {html} = Lit;
19
+ const {render, html} = Lit;
21
20
 
22
21
  const UIStrings = {
23
22
  /**
@@ -62,37 +61,110 @@ interface CPUThrottlingGroup {
62
61
  showCustomAddOption?: boolean;
63
62
  }
64
63
 
65
- export class CPUThrottlingSelector extends HTMLElement {
66
- readonly #shadow = this.attachShadow({mode: 'open'});
64
+ interface ViewInput {
65
+ recommendedOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null;
66
+ currentOption: SDK.CPUThrottlingManager.CPUThrottlingOption;
67
+ groups: CPUThrottlingGroup[];
68
+ throttling: SDK.CPUThrottlingManager.CalibratedCPUThrottling;
69
+ onMenuItemSelected: (event: Menus.SelectMenu.SelectMenuItemSelectedEvent) => void;
70
+ onCalibrateClick: () => void;
71
+ }
72
+
73
+ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
74
+ let recommendedInfoEl;
75
+ if (input.recommendedOption && input.currentOption === SDK.CPUThrottlingManager.NoThrottlingOption) {
76
+ recommendedInfoEl = html`<devtools-icon
77
+ title=${i18nString(UIStrings.recommendedThrottlingReason)}
78
+ name=info></devtools-icon>`;
79
+ }
67
80
 
81
+ const selectionTitle = input.currentOption.title();
82
+ const hasCalibratedOnce = input.throttling.low || input.throttling.mid;
83
+ const calibrationLabel = hasCalibratedOnce ? i18nString(UIStrings.recalibrate) : i18nString(UIStrings.calibrate);
84
+
85
+ // clang-format off
86
+ /* eslint-disable rulesdir/no-deprecated-component-usages */
87
+ const template = html`
88
+ <style>${cpuThrottlingSelectorStyles}</style>
89
+ <devtools-select-menu
90
+ @selectmenuselected=${input.onMenuItemSelected}
91
+ .showDivider=${true}
92
+ .showArrow=${true}
93
+ .sideButton=${false}
94
+ .showSelectedItem=${true}
95
+ .jslogContext=${'cpu-throttling'}
96
+ .buttonTitle=${i18nString(UIStrings.cpu, {PH1: selectionTitle})}
97
+ .title=${i18nString(UIStrings.cpuThrottling, {PH1: selectionTitle})}
98
+ >
99
+ ${input.groups.map(group => {
100
+ return html`
101
+ <devtools-menu-group .name=${group.name} .title=${group.name}>
102
+ ${group.items.map(option => {
103
+ const title = option === input.recommendedOption ? i18nString(UIStrings.recommendedThrottling, {PH1: option.title()}) : option.title();
104
+ const rate = option.rate();
105
+ return html`
106
+ <devtools-menu-item
107
+ .value=${option.calibratedDeviceType ?? rate}
108
+ .selected=${input.currentOption === option}
109
+ .disabled=${rate === 0}
110
+ .title=${title}
111
+ jslog=${VisualLogging.item(option.jslogContext).track({click: true})}
112
+ >
113
+ ${title}
114
+ </devtools-menu-item>
115
+ `;
116
+ })}
117
+ ${group.name === 'Calibrated presets' ? html`<devtools-menu-item
118
+ .value=${-1 /* This won't be displayed unless it has some value. */}
119
+ .title=${calibrationLabel}
120
+ jslog=${VisualLogging.action('cpu-throttling-selector-calibrate').track({click: true})}
121
+ @click=${input.onCalibrateClick}
122
+ >
123
+ ${calibrationLabel}
124
+ </devtools-menu-item>` : Lit.nothing}
125
+ </devtools-menu-group>`;
126
+ })}
127
+ </devtools-select-menu>
128
+ ${recommendedInfoEl}
129
+ `;
130
+ // clang-format on
131
+ render(template, target);
132
+ };
133
+
134
+ type View = typeof DEFAULT_VIEW;
135
+
136
+ export class CPUThrottlingSelector extends UI.Widget.Widget {
68
137
  #currentOption: SDK.CPUThrottlingManager.CPUThrottlingOption;
69
138
  #recommendedOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null = null;
70
139
  #groups: CPUThrottlingGroup[] = [];
71
140
  #calibratedThrottlingSetting: Common.Settings.Setting<SDK.CPUThrottlingManager.CalibratedCPUThrottling>;
141
+ readonly #view: View;
72
142
 
73
- constructor() {
74
- super();
143
+ constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
144
+ super(element);
75
145
  this.#currentOption = SDK.CPUThrottlingManager.CPUThrottlingManager.instance().cpuThrottlingOption();
76
146
  this.#calibratedThrottlingSetting =
77
147
  Common.Settings.Settings.instance().createSetting<SDK.CPUThrottlingManager.CalibratedCPUThrottling>(
78
148
  'calibrated-cpu-throttling', {}, Common.Settings.SettingStorageType.GLOBAL);
79
149
  this.#resetGroups();
80
- this.#render();
150
+ this.#view = view;
81
151
  }
82
152
 
83
153
  set recommendedOption(recommendedOption: SDK.CPUThrottlingManager.CPUThrottlingOption|null) {
84
154
  this.#recommendedOption = recommendedOption;
85
- void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
155
+ this.requestUpdate();
86
156
  }
87
157
 
88
- connectedCallback(): void {
158
+ override wasShown(): void {
159
+ super.wasShown();
89
160
  SDK.CPUThrottlingManager.CPUThrottlingManager.instance().addEventListener(
90
161
  SDK.CPUThrottlingManager.Events.RATE_CHANGED, this.#onOptionChange, this);
91
162
  this.#calibratedThrottlingSetting.addChangeListener(this.#onCalibratedSettingChanged, this);
92
163
  this.#onOptionChange();
93
164
  }
94
165
 
95
- disconnectedCallback(): void {
166
+ override willHide(): void {
167
+ super.willHide();
96
168
  this.#calibratedThrottlingSetting.removeChangeListener(this.#onCalibratedSettingChanged, this);
97
169
  SDK.CPUThrottlingManager.CPUThrottlingManager.instance().removeEventListener(
98
170
  SDK.CPUThrottlingManager.Events.RATE_CHANGED, this.#onOptionChange, this);
@@ -101,12 +173,12 @@ export class CPUThrottlingSelector extends HTMLElement {
101
173
  #onOptionChange(): void {
102
174
  this.#currentOption = SDK.CPUThrottlingManager.CPUThrottlingManager.instance().cpuThrottlingOption();
103
175
 
104
- void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
176
+ this.requestUpdate();
105
177
  }
106
178
 
107
179
  #onCalibratedSettingChanged(): void {
108
180
  this.#resetGroups();
109
- void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
181
+ this.requestUpdate();
110
182
  }
111
183
 
112
184
  #onMenuItemSelected(event: Menus.SelectMenu.SelectMenuItemSelectedEvent): void {
@@ -147,74 +219,15 @@ export class CPUThrottlingSelector extends HTMLElement {
147
219
  ];
148
220
  }
149
221
 
150
- #render = (): void => {
151
- let recommendedInfoEl;
152
- if (this.#recommendedOption && this.#currentOption === SDK.CPUThrottlingManager.NoThrottlingOption) {
153
- recommendedInfoEl = html`<devtools-icon
154
- title=${i18nString(UIStrings.recommendedThrottlingReason)}
155
- name=info></devtools-icon>`;
156
- }
157
-
158
- const selectionTitle = this.#currentOption.title();
159
- const setting = this.#calibratedThrottlingSetting.get();
160
- const hasCalibratedOnce = setting.low || setting.mid;
161
- const calibrationLabel = hasCalibratedOnce ? i18nString(UIStrings.recalibrate) : i18nString(UIStrings.calibrate);
162
-
163
- // clang-format off
164
- /* eslint-disable rulesdir/no-deprecated-component-usages */
165
- const output = html`
166
- <style>${cpuThrottlingSelectorStyles}</style>
167
- <devtools-select-menu
168
- @selectmenuselected=${this.#onMenuItemSelected}
169
- .showDivider=${true}
170
- .showArrow=${true}
171
- .sideButton=${false}
172
- .showSelectedItem=${true}
173
- .jslogContext=${'cpu-throttling'}
174
- .buttonTitle=${i18nString(UIStrings.cpu, {PH1: selectionTitle})}
175
- .title=${i18nString(UIStrings.cpuThrottling, {PH1: selectionTitle})}
176
- >
177
- ${this.#groups.map(group => {
178
- return html`
179
- <devtools-menu-group .name=${group.name} .title=${group.name}>
180
- ${group.items.map(option => {
181
- const title = option === this.#recommendedOption ? i18nString(UIStrings.recommendedThrottling, {PH1: option.title()}) : option.title();
182
- const rate = option.rate();
183
- return html`
184
- <devtools-menu-item
185
- .value=${option.calibratedDeviceType ?? rate}
186
- .selected=${this.#currentOption === option}
187
- .disabled=${rate === 0}
188
- .title=${title}
189
- jslog=${VisualLogging.item(option.jslogContext).track({click: true})}
190
- >
191
- ${title}
192
- </devtools-menu-item>
193
- `;
194
- })}
195
- ${group.name === 'Calibrated presets' ? html`<devtools-menu-item
196
- .value=${-1 /* This won't be displayed unless it has some value. */}
197
- .title=${calibrationLabel}
198
- jslog=${VisualLogging.action('cpu-throttling-selector-calibrate').track({click: true})}
199
- @click=${this.#onCalibrateClick}
200
- >
201
- ${calibrationLabel}
202
- </devtools-menu-item>` : Lit.nothing}
203
- </devtools-menu-group>`;
204
- })}
205
- </devtools-select-menu>
206
- ${recommendedInfoEl}
207
- `;
208
- /* eslint-enable rulesdir/no-deprecated-component-usages */
209
- // clang-format on
210
- Lit.render(output, this.#shadow, {host: this});
211
- };
212
- }
213
-
214
- customElements.define('devtools-cpu-throttling-selector', CPUThrottlingSelector);
215
-
216
- declare global {
217
- interface HTMLElementTagNameMap {
218
- 'devtools-cpu-throttling-selector': CPUThrottlingSelector;
222
+ override async performUpdate(): Promise<void> {
223
+ const input: ViewInput = {
224
+ recommendedOption: this.#recommendedOption,
225
+ currentOption: this.#currentOption,
226
+ groups: this.#groups,
227
+ throttling: this.#calibratedThrottlingSetting.get(),
228
+ onMenuItemSelected: this.#onMenuItemSelected.bind(this),
229
+ onCalibrateClick: this.#onCalibrateClick.bind(this),
230
+ };
231
+ this.#view(input, undefined, this.contentElement);
219
232
  }
220
233
  }
@@ -5,7 +5,6 @@
5
5
  /* eslint-disable rulesdir/no-lit-render-outside-of-view */
6
6
 
7
7
  import '../../../ui/components/icon_button/icon_button.js';
8
- import './CPUThrottlingSelector.js';
9
8
  import './FieldSettingsDialog.js';
10
9
  import './NetworkThrottlingSelector.js';
11
10
  import '../../../ui/components/menus/menus.js';
@@ -30,6 +29,7 @@ import * as Lit from '../../../ui/lit/lit.js';
30
29
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
31
30
  import {getThrottlingRecommendations} from '../utils/Helpers.js';
32
31
 
32
+ import {CPUThrottlingSelector} from './CPUThrottlingSelector.js';
33
33
  import {md} from './insights/Helpers.js';
34
34
  import liveMetricsViewStyles from './liveMetricsView.css.js';
35
35
  import type {MetricCardData} from './MetricCard.js';
@@ -638,7 +638,7 @@ export class LiveMetricsView extends LegacyWrapper.LegacyWrapper.WrappableCompon
638
638
  </ul>
639
639
  ` : nothing}
640
640
  <div class="environment-option">
641
- <devtools-cpu-throttling-selector .recommendedOption=${recs.cpuOption}></devtools-cpu-throttling-selector>
641
+ <devtools-widget .widgetConfig=${UI.Widget.widgetConfig(CPUThrottlingSelector, {recommendedOption: recs.cpuOption})}></devtools-widget>
642
642
  </div>
643
643
  <div class="environment-option">
644
644
  <devtools-network-throttling-selector .recommendedConditions=${recs.networkConditions}></devtools-network-throttling-selector>