chrome-devtools-frontend 1.0.1643855 → 1.0.1646286

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 (95) hide show
  1. package/.agents/skills/devtools-source-maps/SKILL.md +124 -0
  2. package/docs/README.md +1 -0
  3. package/docs/using_source_maps.md +159 -0
  4. package/front_end/core/host/AidaClientTypes.ts +2 -0
  5. package/front_end/core/host/UserMetrics.ts +5 -3
  6. package/front_end/core/root/Runtime.ts +10 -0
  7. package/front_end/core/sdk/CSSPropertyParserMatchers.ts +2 -3
  8. package/front_end/core/sdk/DebuggerModel.ts +7 -9
  9. package/front_end/core/sdk/NetworkRequest.ts +0 -25
  10. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +37 -0
  11. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  12. package/front_end/generated/SupportedCSSProperties.js +79 -2
  13. package/front_end/generated/protocol.ts +0 -5
  14. package/front_end/models/ai_assistance/AiAgent2.ts +52 -15
  15. package/front_end/models/ai_assistance/AiConversation.ts +4 -2
  16. package/front_end/models/ai_assistance/AiOrigins.ts +63 -2
  17. package/front_end/models/ai_assistance/README.md +20 -8
  18. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +2 -2
  19. package/front_end/models/ai_assistance/agents/FileAgent.ts +9 -42
  20. package/front_end/models/ai_assistance/agents/NetworkAgent.snapshot.txt +2 -2
  21. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +9 -133
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +25 -2
  23. package/front_end/models/ai_assistance/agents/README.md +64 -0
  24. package/front_end/models/ai_assistance/agents/StylingAgent.ts +26 -3
  25. package/front_end/models/ai_assistance/ai_assistance.ts +4 -0
  26. package/front_end/models/ai_assistance/contexts/FileContext.ts +45 -0
  27. package/front_end/models/ai_assistance/contexts/RequestContext.snapshot.txt +48 -0
  28. package/front_end/models/ai_assistance/contexts/RequestContext.ts +116 -0
  29. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +2 -1
  30. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +9 -12
  31. package/front_end/models/ai_assistance/tools/GetStyles.ts +19 -12
  32. package/front_end/models/ai_assistance/tools/README.md +45 -0
  33. package/front_end/models/ai_assistance/tools/Tool.ts +74 -11
  34. package/front_end/models/ai_assistance/tools/ToolRegistry.ts +21 -5
  35. package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +18 -2
  36. package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +4 -0
  37. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +17 -4
  38. package/front_end/models/stack_trace/StackTraceModel.ts +34 -1
  39. package/front_end/models/trace/Styles.ts +29 -7
  40. package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +15 -11
  41. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +33 -4
  42. package/front_end/models/trace/helpers/Timing.ts +10 -0
  43. package/front_end/models/trace/types/TraceEvents.ts +22 -2
  44. package/front_end/models/web_mcp/WebMCPModel.ts +8 -48
  45. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +21 -15
  46. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +16 -0
  47. package/front_end/panels/ai_assistance/components/ChatInput.ts +4 -4
  48. package/front_end/panels/application/ApplicationPanelSidebar.ts +69 -0
  49. package/front_end/panels/application/ServiceWorkersView.ts +2 -2
  50. package/front_end/panels/application/WebMCPView.ts +40 -71
  51. package/front_end/panels/application/components/AdsView.ts +31 -28
  52. package/front_end/panels/application/components/BackForwardCacheView.ts +1 -2
  53. package/front_end/panels/application/components/adsView.css +6 -0
  54. package/front_end/panels/common/ExtensionServer.ts +5 -0
  55. package/front_end/panels/console/ConsoleView.ts +6 -1
  56. package/front_end/panels/console/ConsoleViewMessage.ts +46 -213
  57. package/front_end/panels/console/SymbolizedErrorWidget.ts +4 -1
  58. package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +0 -1
  59. package/front_end/panels/elements/ElementsTreeElement.ts +0 -2
  60. package/front_end/panels/elements/PropertyRenderer.ts +0 -1
  61. package/front_end/panels/elements/StylesSidebarPane.ts +9 -2
  62. package/front_end/panels/issues/AffectedResourcesView.ts +1 -1
  63. package/front_end/panels/issues/AffectedSourcesView.ts +1 -1
  64. package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +0 -1
  65. package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -0
  66. package/front_end/panels/network/NetworkDataGridNode.ts +1 -2
  67. package/front_end/panels/network/NetworkLogView.ts +34 -7
  68. package/front_end/panels/profiler/HeapProfileView.ts +0 -1
  69. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +0 -1
  70. package/front_end/panels/profiler/HeapSnapshotView.ts +1 -1
  71. package/front_end/panels/profiler/IsolateSelector.ts +4 -2
  72. package/front_end/panels/profiler/ProfileLauncherView.ts +194 -126
  73. package/front_end/panels/profiler/ProfilesPanel.ts +1 -3
  74. package/front_end/panels/settings/components/SyncSection.ts +1 -1
  75. package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -4
  76. package/front_end/panels/timeline/TimelinePanel.ts +7 -0
  77. package/front_end/panels/timeline/TimelineUIUtils.ts +13 -14
  78. package/front_end/panels/timeline/TimingsTrackAppender.ts +7 -5
  79. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +0 -1
  80. package/front_end/panels/timeline/components/NetworkRequestDetails.ts +0 -2
  81. package/front_end/panels/timeline/components/insights/ForcedReflow.ts +0 -1
  82. package/front_end/panels/timeline/components/insights/NodeLink.ts +0 -1
  83. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -0
  84. package/front_end/third_party/chromium/README.chromium +1 -1
  85. package/front_end/ui/helpers/OpenInNewTab.ts +3 -3
  86. package/front_end/ui/kit/link/Link.ts +16 -2
  87. package/front_end/ui/legacy/InspectorDrawerView.ts +14 -5
  88. package/front_end/ui/legacy/InspectorView.ts +4 -1
  89. package/front_end/ui/legacy/PlusButton.ts +6 -1
  90. package/front_end/ui/legacy/Widget.ts +19 -1
  91. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +95 -31
  92. package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +0 -1
  93. package/front_end/ui/legacy/components/utils/Linkifier.ts +2 -16
  94. package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
  95. package/package.json +1 -1
@@ -1,12 +1,13 @@
1
1
  // Copyright 2011 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 @devtools/no-imperative-dom-api */
5
4
 
6
5
  import * as Common from '../../core/common/common.js';
7
6
  import * as i18n from '../../core/i18n/i18n.js';
8
7
  import * as Buttons from '../../ui/components/buttons/buttons.js';
9
8
  import * as UI from '../../ui/legacy/legacy.js';
9
+ import {html, nothing, render} from '../../ui/lit/lit.js';
10
+ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
10
11
 
11
12
  import {IsolateSelector} from './IsolateSelector.js';
12
13
  import type {ProfileType} from './ProfileHeader.js';
@@ -41,166 +42,233 @@ const UIStrings = {
41
42
  } as const;
42
43
  const str_ = i18n.i18n.registerUIStrings('panels/profiler/ProfileLauncherView.ts', UIStrings);
43
44
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
45
+ const {widget, widgetRef} = UI.Widget;
46
+
47
+ interface ProfileTypeEntry {
48
+ profileType: ProfileType;
49
+ selected: boolean;
50
+ customContent: Element|null;
51
+ }
52
+
53
+ export interface ViewInput {
54
+ headerText: string;
55
+ profileTypes: ProfileTypeEntry[];
56
+ controlButtonText: string;
57
+ controlButtonDisabled: boolean;
58
+ controlButtonTooltip: string;
59
+ isProfiling: boolean;
60
+ isolateSelector: IsolateSelector|null;
61
+ onControlClick: () => void;
62
+ onLoadClick: () => void;
63
+ onProfileTypeChange: (profileType: ProfileType) => void;
64
+ }
65
+
66
+ export interface ViewOutput {
67
+ isolateSelector: IsolateSelector;
68
+ }
69
+
70
+ export type View = (input: ViewInput, output: ViewOutput, target: HTMLElement) => void;
71
+
72
+ // clang-format off
73
+ export const DEFAULT_VIEW: View = (input, output, target) => {
74
+ render(html`
75
+ <style>${profileLauncherViewStyles}</style>
76
+ <div class="profile-launcher-view-content vbox">
77
+ <div class="vbox">
78
+ <h1>${input.headerText}</h1>
79
+ <form role="radiogroup" aria-label=${input.headerText}>
80
+ ${input.profileTypes.map(entry => {
81
+ const radioId = `profile-type-${entry.profileType.id}`;
82
+ const customContent = entry.customContent;
83
+ return html`
84
+ <input id=${radioId} type="radio" name="profile-type"
85
+ .checked=${entry.selected}
86
+ ?disabled=${input.isProfiling}
87
+ @change=${() => input.onProfileTypeChange(entry.profileType)}
88
+ jslog=${VisualLogging.toggle().track({change: true}).context('profiler.profile-type')}
89
+ />
90
+ <label for=${radioId}>${entry.profileType.name}</label>
91
+ <p>${entry.profileType.description}</p>
92
+ ${customContent ? html`
93
+ <p>
94
+ <span role="group" aria-labelledby=${radioId}>
95
+ ${customContent}
96
+ </span>
97
+ </p>
98
+ ` : nothing}
99
+ `;
100
+ })}
101
+ </form>
102
+ </div>
103
+ <div class="vbox profile-isolate-selector-block">
104
+ <h1>${i18nString(UIStrings.selectJavascriptVmInstance)}</h1>
105
+ <div class="vbox profile-launcher-target-list profile-launcher-target-list-container">
106
+ <devtools-widget
107
+ ${widget(IsolateSelector)}
108
+ ${widgetRef(IsolateSelector, e => {output.isolateSelector = e;})}
109
+ ></devtools-widget>
110
+ </div>
111
+ ${input.isolateSelector?.totalMemoryElement() ?? nothing}
112
+ </div>
113
+ <div class="hbox profile-launcher-buttons">
114
+ <devtools-button
115
+ .variant=${Buttons.Button.Variant.OUTLINED}
116
+ .iconName=${'import'}
117
+ @click=${input.onLoadClick}
118
+ .jslogContext=${'profiler.load-from-file'}
119
+ >${i18nString(UIStrings.load)}</devtools-button>
120
+ <devtools-button
121
+ .variant=${Buttons.Button.Variant.PRIMARY}
122
+ ?disabled=${input.controlButtonDisabled}
123
+ title=${input.controlButtonTooltip}
124
+ @click=${input.onControlClick}
125
+ .jslogContext=${'profiler.heap-toggle-recording'}
126
+ >${input.controlButtonText}</devtools-button>
127
+ </div>
128
+ </div>
129
+ `, target);
130
+ };
131
+ // clang-format on
132
+
44
133
  export class ProfileLauncherView extends Common.ObjectWrapper.eventMixin<EventTypes, typeof UI.Widget.VBox>(
45
134
  UI.Widget.VBox) {
46
135
  readonly panel: ProfilesPanel;
47
- #contentElement: HTMLElement;
48
136
  readonly selectedProfileTypeSetting: Common.Settings.Setting<string>;
49
- profileTypeHeaderElement: HTMLElement;
50
- readonly profileTypeSelectorForm: HTMLElement;
51
- controlButton: Buttons.Button.Button;
52
- readonly loadButton: Buttons.Button.Button;
53
- recordButtonEnabled: boolean;
54
- typeIdToOptionElementAndProfileType: Map<string, {
55
- optionElement: HTMLInputElement,
56
- profileType: ProfileType,
57
- }>;
58
- isProfiling?: boolean;
59
- isInstantProfile?: boolean;
60
- isEnabled?: boolean;
61
-
62
- constructor(profilesPanel: ProfilesPanel) {
63
- super();
64
- this.registerRequiredCSS(profileLauncherViewStyles);
137
+ readonly #view: View;
138
+ #isolateSelector: IsolateSelector|null = null;
139
+ #profileTypes = new Map<string, ProfileType>();
140
+ #isProfiling = false;
141
+ #isInstantProfile = false;
142
+ #isEnabled = false;
143
+ #recordButtonEnabled = true;
144
+ #selectedTypeId = '';
65
145
 
66
- this.panel = profilesPanel;
67
- this.element.classList.add('profile-launcher-view');
68
- this.#contentElement = this.element.createChild('div', 'profile-launcher-view-content vbox');
146
+ constructor(profilesPanel: ProfilesPanel, view: View = DEFAULT_VIEW) {
147
+ super({classes: ['profile-launcher-view']});
69
148
 
70
- const profileTypeSelectorElement = this.#contentElement.createChild('div', 'vbox');
149
+ this.#view = view;
150
+ this.panel = profilesPanel;
71
151
  this.selectedProfileTypeSetting = Common.Settings.Settings.instance().createSetting('selected-profile-type', 'CPU');
72
- this.profileTypeHeaderElement = profileTypeSelectorElement.createChild('h1');
73
- this.profileTypeSelectorForm = profileTypeSelectorElement.createChild('form');
74
- UI.ARIAUtils.markAsRadioGroup(this.profileTypeSelectorForm);
75
-
76
- const isolateSelectorElement = this.#contentElement.createChild('div', 'vbox profile-isolate-selector-block');
77
- isolateSelectorElement.createChild('h1').textContent = i18nString(UIStrings.selectJavascriptVmInstance);
78
- const isolateSelector = new IsolateSelector();
79
- const isolateSelectorElementChild = isolateSelectorElement.createChild('div', 'vbox profile-launcher-target-list');
80
- isolateSelectorElementChild.classList.add('profile-launcher-target-list-container');
81
- isolateSelector.show(isolateSelectorElementChild);
82
- isolateSelectorElement.appendChild(isolateSelector.totalMemoryElement());
83
-
84
- const buttonsDiv = this.#contentElement.createChild('div', 'hbox profile-launcher-buttons');
85
- this.controlButton = UI.UIUtils.createTextButton('', this.controlButtonClicked.bind(this), {
86
- jslogContext: 'profiler.heap-toggle-recording',
87
- variant: Buttons.Button.Variant.PRIMARY,
88
- });
89
- this.loadButton = new Buttons.Button.Button();
90
- this.loadButton
91
- .data = {iconName: 'import', variant: Buttons.Button.Variant.OUTLINED, jslogContext: 'profiler.load-from-file'};
92
- this.loadButton.textContent = i18nString(UIStrings.load);
93
- this.loadButton.addEventListener('click', this.loadButtonClicked.bind(this));
94
- buttonsDiv.appendChild(this.loadButton);
95
- buttonsDiv.appendChild(this.controlButton);
96
- this.recordButtonEnabled = true;
97
-
98
- this.typeIdToOptionElementAndProfileType = new Map();
99
152
  }
100
153
 
101
- loadButtonClicked(): void {
102
- const loadFromFileAction = UI.ActionRegistry.ActionRegistry.instance().getAction('profiler.load-from-file');
103
- void loadFromFileAction.execute();
154
+ override wasShown(): void {
155
+ super.wasShown();
156
+ this.requestUpdate();
104
157
  }
105
158
 
106
- updateControls(): void {
107
- if (this.isEnabled && this.recordButtonEnabled) {
108
- this.controlButton.removeAttribute('disabled');
109
- } else {
110
- this.controlButton.setAttribute('disabled', '');
111
- }
112
- UI.Tooltip.Tooltip.install(
113
- this.controlButton, this.recordButtonEnabled ? '' : UI.UIUtils.anotherProfilerActiveLabel());
114
- if (this.isInstantProfile) {
115
- this.controlButton.classList.remove('running');
116
- this.controlButton.textContent = i18nString(UIStrings.takeSnapshot);
117
- } else if (this.isProfiling) {
118
- this.controlButton.classList.add('running');
119
- this.controlButton.textContent = i18nString(UIStrings.stop);
120
- } else {
121
- this.controlButton.classList.remove('running');
122
- this.controlButton.textContent = i18nString(UIStrings.start);
123
- }
124
- for (const {optionElement} of this.typeIdToOptionElementAndProfileType.values()) {
125
- optionElement.disabled = Boolean(this.isProfiling);
126
- }
159
+ #getHeaderText(): string {
160
+ return this.#profileTypes.size > 1 ? i18nString(UIStrings.selectProfilingType) :
161
+ (this.#profileTypes.values().next().value?.name ?? '');
127
162
  }
128
163
 
129
164
  profileStarted(): void {
130
- this.isProfiling = true;
131
- this.updateControls();
165
+ this.#isProfiling = true;
166
+ this.requestUpdate();
132
167
  }
133
168
 
134
169
  profileFinished(): void {
135
- this.isProfiling = false;
136
- this.updateControls();
170
+ this.#isProfiling = false;
171
+ this.requestUpdate();
137
172
  }
138
173
 
139
174
  updateProfileType(profileType: ProfileType, recordButtonEnabled: boolean): void {
140
- this.isInstantProfile = profileType.isInstantProfile();
141
- this.recordButtonEnabled = recordButtonEnabled;
142
- this.isEnabled = profileType.isEnabled();
143
- this.updateControls();
175
+ this.#isInstantProfile = profileType.isInstantProfile();
176
+ this.#recordButtonEnabled = recordButtonEnabled;
177
+ this.#isEnabled = profileType.isEnabled();
178
+ this.requestUpdate();
144
179
  }
145
180
 
146
181
  addProfileType(profileType: ProfileType): void {
147
- const {radio, label} = UI.UIUtils.createRadioButton('profile-type', profileType.name, 'profiler.profile-type');
148
- this.profileTypeSelectorForm.appendChild(label);
149
- this.typeIdToOptionElementAndProfileType.set(profileType.id, {optionElement: radio, profileType});
150
- radio.addEventListener('change', this.profileTypeChanged.bind(this, profileType), false);
151
- const descriptionElement = this.profileTypeSelectorForm.createChild('p');
152
- descriptionElement.textContent = profileType.description;
153
- UI.ARIAUtils.setDescription(radio, profileType.description);
154
- const customContent = profileType.customContent();
155
- if (customContent) {
156
- customContent.setAttribute('role', 'group');
157
- customContent.setAttribute('aria-labelledby', `${radio.id}`);
158
- this.profileTypeSelectorForm.createChild('p').appendChild(customContent);
159
- profileType.setCustomContentEnabled(false);
160
- }
161
- const headerText = this.typeIdToOptionElementAndProfileType.size > 1 ? i18nString(UIStrings.selectProfilingType) :
162
- profileType.name;
163
- this.profileTypeHeaderElement.textContent = headerText;
164
- UI.ARIAUtils.setLabel(this.profileTypeSelectorForm, headerText);
182
+ this.#profileTypes.set(profileType.id, profileType);
183
+ profileType.setCustomContentEnabled(false);
184
+ this.requestUpdate();
165
185
  }
166
186
 
167
187
  restoreSelectedProfileType(): void {
168
188
  let typeId = this.selectedProfileTypeSetting.get();
169
- if (!this.typeIdToOptionElementAndProfileType.has(typeId)) {
170
- typeId = this.typeIdToOptionElementAndProfileType.keys().next().value as string;
189
+ if (!this.#profileTypes.has(typeId)) {
190
+ typeId = this.#profileTypes.keys().next().value as string;
171
191
  this.selectedProfileTypeSetting.set(typeId);
172
192
  }
173
193
 
174
- const optionElementAndProfileType = (this.typeIdToOptionElementAndProfileType.get(typeId) as {
175
- optionElement: HTMLInputElement,
176
- profileType: ProfileType,
177
- });
178
- optionElementAndProfileType.optionElement.checked = true;
179
- const type = optionElementAndProfileType.profileType;
180
- for (const [id, {profileType}] of this.typeIdToOptionElementAndProfileType) {
181
- const enabled = (id === typeId);
182
- profileType.setCustomContentEnabled(enabled);
194
+ this.#selectedTypeId = typeId;
195
+ const selectedType = this.#profileTypes.get(typeId);
196
+ if (!selectedType) {
197
+ return;
183
198
  }
184
- this.dispatchEventToListeners(Events.PROFILE_TYPE_SELECTED, type);
185
- }
186
-
187
- controlButtonClicked(): void {
188
- this.panel.toggleRecord();
199
+ for (const [id, profileType] of this.#profileTypes) {
200
+ profileType.setCustomContentEnabled(id === typeId);
201
+ }
202
+ this.dispatchEventToListeners(Events.PROFILE_TYPE_SELECTED, selectedType);
203
+ this.requestUpdate();
189
204
  }
190
205
 
191
- profileTypeChanged(profileType: ProfileType): void {
192
- const typeId = this.selectedProfileTypeSetting.get();
193
- const type = (this.typeIdToOptionElementAndProfileType.get(typeId) as {
194
- optionElement: HTMLInputElement,
195
- profileType: ProfileType,
196
- }).profileType;
197
- type.setCustomContentEnabled(false);
206
+ #profileTypeChanged(profileType: ProfileType): void {
207
+ const previousTypeId = this.#selectedTypeId;
208
+ const previousType = this.#profileTypes.get(previousTypeId);
209
+ if (previousType) {
210
+ previousType.setCustomContentEnabled(false);
211
+ }
198
212
  profileType.setCustomContentEnabled(true);
199
- this.dispatchEventToListeners(Events.PROFILE_TYPE_SELECTED, profileType);
200
- this.isInstantProfile = profileType.isInstantProfile();
201
- this.isEnabled = profileType.isEnabled();
202
- this.updateControls();
213
+ this.#selectedTypeId = profileType.id;
203
214
  this.selectedProfileTypeSetting.set(profileType.id);
215
+ this.#isInstantProfile = profileType.isInstantProfile();
216
+ this.#isEnabled = profileType.isEnabled();
217
+ this.dispatchEventToListeners(Events.PROFILE_TYPE_SELECTED, profileType);
218
+ this.requestUpdate();
219
+ }
220
+
221
+ override performUpdate(): void {
222
+ const profileTypeEntries: ProfileTypeEntry[] = [];
223
+ for (const [id, profileType] of this.#profileTypes) {
224
+ const selected = id === this.#selectedTypeId;
225
+ const customContent = profileType.customContent();
226
+ profileType.setCustomContentEnabled(selected);
227
+ profileTypeEntries.push({
228
+ profileType,
229
+ selected,
230
+ customContent,
231
+ });
232
+ }
233
+
234
+ const controlButtonText = this.#isInstantProfile ?
235
+ i18nString(UIStrings.takeSnapshot) :
236
+ (this.#isProfiling ? i18nString(UIStrings.stop) : i18nString(UIStrings.start));
237
+ const controlButtonDisabled = !(this.#isEnabled && this.#recordButtonEnabled);
238
+ const controlButtonTooltip = this.#recordButtonEnabled ? '' : UI.UIUtils.anotherProfilerActiveLabel();
239
+ const that = this;
240
+
241
+ this.#view(
242
+ {
243
+ headerText: this.#getHeaderText(),
244
+ profileTypes: profileTypeEntries,
245
+ controlButtonText,
246
+ controlButtonDisabled,
247
+ controlButtonTooltip,
248
+ isProfiling: this.#isProfiling,
249
+ isolateSelector: this.#isolateSelector,
250
+ onControlClick: () => {
251
+ this.panel.toggleRecord();
252
+ },
253
+ onLoadClick: () => {
254
+ const loadFromFileAction = UI.ActionRegistry.ActionRegistry.instance().getAction('profiler.load-from-file');
255
+ void loadFromFileAction.execute();
256
+ },
257
+ onProfileTypeChange: (profileType: ProfileType) => {
258
+ this.#profileTypeChanged(profileType);
259
+ },
260
+ },
261
+ {
262
+ set isolateSelector(isolateSelector: IsolateSelector) {
263
+ if (that.#isolateSelector === isolateSelector) {
264
+ return;
265
+ }
266
+ that.#isolateSelector = isolateSelector;
267
+ that.requestUpdate();
268
+ },
269
+ },
270
+ this.contentElement,
271
+ );
204
272
  }
205
273
  }
206
274
 
@@ -357,7 +357,7 @@ export class ProfilesPanel extends UI.Panel.PanelWithSidebar implements DataDisp
357
357
  reset(): void {
358
358
  this.profileTypes.forEach(type => type.reset());
359
359
 
360
- delete this.visibleView;
360
+ this.closeVisibleView();
361
361
 
362
362
  this.profileGroups = {};
363
363
  this.updateToggleRecordAction(false);
@@ -365,8 +365,6 @@ export class ProfilesPanel extends UI.Panel.PanelWithSidebar implements DataDisp
365
365
 
366
366
  this.sidebarTree.element.classList.remove('some-expandable');
367
367
 
368
- this.launcherView.detach();
369
- this.profileViews.removeChildren();
370
368
  this.profileViewToolbar.removeToolbarItems();
371
369
 
372
370
  this.profilesItemTreeElement.select();
@@ -346,7 +346,7 @@ export class SyncSection extends UI.Widget.Widget {
346
346
  // TODO: investigate if /advance link is alive
347
347
  const warningLink =
348
348
  this.#syncInfo.isSyncActive ? 'chrome://settings/syncSetup/advanced' : 'chrome://settings/syncSetup';
349
- UIHelpers.openInNewTab(warningLink);
349
+ UIHelpers.openInNewTab(warningLink, /* allowPrivileged=*/ true);
350
350
  event.consume();
351
351
  }
352
352
 
@@ -69,9 +69,10 @@ export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
69
69
  [Trace.Types.Events.Name.SOFT_NAVIGATION_START]: 1,
70
70
  [Trace.Types.Events.Name.MARK_LOAD]: 2,
71
71
  [Trace.Types.Events.Name.MARK_FCP]: 3,
72
- [Trace.Types.Events.Name.MARK_DOM_CONTENT]: 4,
73
- [Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 5,
74
- [Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 6,
72
+ [Trace.Types.Events.Name.MARK_SOFT_FCP]: 4,
73
+ [Trace.Types.Events.Name.MARK_DOM_CONTENT]: 5,
74
+ [Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 6,
75
+ [Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 7,
75
76
  };
76
77
 
77
78
  // Threshold to match up overlay markers that are off by a tiny amount so they aren't rendered
@@ -676,7 +677,7 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
676
677
  event.name === Trace.Types.Events.Name.SOFT_NAVIGATION_START ||
677
678
  event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE ||
678
679
  event.name === Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION ||
679
- event.name === Trace.Types.Events.Name.MARK_FCP ||
680
+ event.name === Trace.Types.Events.Name.MARK_FCP || event.name === Trace.Types.Events.Name.MARK_SOFT_FCP ||
680
681
  event.name === Trace.Types.Events.Name.MARK_DOM_CONTENT ||
681
682
  event.name === Trace.Types.Events.Name.MARK_LOAD);
682
683
 
@@ -2435,6 +2435,13 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
2435
2435
  async loadingStarted(): Promise<void> {
2436
2436
  this.#changeView({mode: 'STATUS_PANE_OVERLAY'});
2437
2437
 
2438
+ // If recording was stopped automatically (e.g. page reload or AI-triggered trace),
2439
+ // we must transition to STOP_PENDING so that loadingComplete() knows the resulting
2440
+ // trace is a fresh recording.
2441
+ if (this.state === State.RECORDING) {
2442
+ this.setState(State.STOP_PENDING);
2443
+ }
2444
+
2438
2445
  if (this.statusDialog) {
2439
2446
  this.statusDialog.remove();
2440
2447
  }
@@ -668,7 +668,6 @@ export class TimelineUIUtils {
668
668
  const options = {
669
669
  tabStop: true,
670
670
  showColumnNumber: false,
671
- inlineFrameIndex: 0,
672
671
  };
673
672
  details = LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options);
674
673
  }
@@ -763,7 +762,6 @@ export class TimelineUIUtils {
763
762
  lineNumber,
764
763
  columnNumber,
765
764
  showColumnNumber: true,
766
- inlineFrameIndex: 0,
767
765
  className: 'timeline-details',
768
766
  tabStop: true,
769
767
  omitOrigin,
@@ -788,14 +786,13 @@ export class TimelineUIUtils {
788
786
  const options = {
789
787
  className: 'timeline-details',
790
788
  tabStop: true,
791
- inlineFrameIndex: 0,
792
789
  showColumnNumber: true,
793
790
  columnNumber: frame.columnNumber,
794
791
  lineNumber: frame.lineNumber,
795
792
  maxLength,
796
793
  };
797
794
  if (isFreshOrEnhanced) {
798
- return linkifier.maybeLinkifyConsoleCallFrame(target, frame, {showColumnNumber: true, inlineFrameIndex: 0});
795
+ return linkifier.maybeLinkifyConsoleCallFrame(target, frame, {showColumnNumber: true});
799
796
  }
800
797
  return LegacyComponents.Linkifier.Linkifier.linkifyURL(frame.url as Platform.DevToolsPath.UrlString, options);
801
798
  }
@@ -809,17 +806,21 @@ export class TimelineUIUtils {
809
806
  name = 'Largest Contentful Paint';
810
807
  break;
811
808
  case Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION:
812
- link = 'https://developer.chrome.com/docs/web-platform/soft-navigations-experiment';
809
+ link = 'https://developer.chrome.com/docs/web-platform/soft-navigations';
813
810
  name = 'Soft Largest Contentful Paint';
814
811
  break;
815
812
  case Trace.Types.Events.Name.SOFT_NAVIGATION_START:
816
- link = 'https://developer.chrome.com/docs/web-platform/soft-navigations-experiment';
813
+ link = 'https://developer.chrome.com/docs/web-platform/soft-navigations';
817
814
  name = 'Soft Navigations';
818
815
  break;
819
816
  case Trace.Types.Events.Name.MARK_FCP:
820
817
  link = 'https://web.dev/first-contentful-paint/';
821
818
  name = 'First Contentful Paint';
822
819
  break;
820
+ case Trace.Types.Events.Name.MARK_SOFT_FCP:
821
+ link = 'https://developer.chrome.com/docs/web-platform/soft-navigations';
822
+ name = 'Soft First Contentful Paint';
823
+ break;
823
824
  default:
824
825
  break;
825
826
  }
@@ -963,7 +964,7 @@ export class TimelineUIUtils {
963
964
 
964
965
  // Add timestamp to user timings, including custom extensibility markers
965
966
  if (Trace.Helpers.Trace.eventHasCategory(event, Trace.Types.Events.Categories.UserTiming) ||
966
- Trace.Types.Extensions.isSyntheticExtensionEntry(event)) {
967
+ Trace.Types.Extensions.isSyntheticExtensionEntry(event) || Trace.Types.Events.isSoftNavigationStart(event)) {
967
968
  const adjustedEventTimeStamp = timeStampForEventAdjustedForClosestNavigationIfPossible(
968
969
  event,
969
970
  parsedTrace,
@@ -1228,7 +1229,6 @@ export class TimelineUIUtils {
1228
1229
  const options = {
1229
1230
  tabStop: true,
1230
1231
  showColumnNumber: false,
1231
- inlineFrameIndex: 0,
1232
1232
  };
1233
1233
  contentHelper.appendElementRow(
1234
1234
  i18nString(UIStrings.imageUrl), LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options));
@@ -1242,7 +1242,6 @@ export class TimelineUIUtils {
1242
1242
  const options = {
1243
1243
  tabStop: true,
1244
1244
  showColumnNumber: false,
1245
- inlineFrameIndex: 0,
1246
1245
  };
1247
1246
  contentHelper.appendElementRow(
1248
1247
  i18nString(UIStrings.stylesheetUrl), LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options));
@@ -1444,6 +1443,7 @@ export class TimelineUIUtils {
1444
1443
 
1445
1444
  case Trace.Types.Events.Name.MARK_FIRST_PAINT:
1446
1445
  case Trace.Types.Events.Name.MARK_FCP:
1446
+ case Trace.Types.Events.Name.MARK_SOFT_FCP:
1447
1447
  case Trace.Types.Events.Name.MARK_LOAD:
1448
1448
  case Trace.Types.Events.Name.MARK_DOM_CONTENT: {
1449
1449
  const adjustedEventTimeStamp = timeStampForEventAdjustedForClosestNavigationIfPossible(
@@ -2074,7 +2074,7 @@ export class TimelineUIUtils {
2074
2074
  tall = true;
2075
2075
  break;
2076
2076
  case Trace.Types.Events.Name.SOFT_NAVIGATION_START:
2077
- color = 'var(--sys-color-blue)';
2077
+ color = 'var(--color-text-primary)';
2078
2078
  tall = true;
2079
2079
  break;
2080
2080
  case Trace.Types.Events.Name.FRAME_STARTED_LOADING:
@@ -2094,6 +2094,7 @@ export class TimelineUIUtils {
2094
2094
  tall = true;
2095
2095
  break;
2096
2096
  case Trace.Types.Events.Name.MARK_FCP:
2097
+ case Trace.Types.Events.Name.MARK_SOFT_FCP:
2097
2098
  color = 'var(--sys-color-green-bright)';
2098
2099
  tall = true;
2099
2100
  break;
@@ -2299,7 +2300,6 @@ export class TimelineDetailsContentHelper {
2299
2300
  tabStop: true,
2300
2301
  columnNumber: startColumn,
2301
2302
  showColumnNumber: true,
2302
- inlineFrameIndex: 0,
2303
2303
  text,
2304
2304
  omitOrigin,
2305
2305
  };
@@ -2316,8 +2316,7 @@ export class TimelineDetailsContentHelper {
2316
2316
  return;
2317
2317
  }
2318
2318
  const locationContent = document.createElement('span');
2319
- const link = this.#linkifier.maybeLinkifyScriptLocation(
2320
- this.target, null, url, startLine, {tabStop: true, inlineFrameIndex: 0});
2319
+ const link = this.#linkifier.maybeLinkifyScriptLocation(this.target, null, url, startLine, {tabStop: true});
2321
2320
  if (!link) {
2322
2321
  return;
2323
2322
  }
@@ -2407,7 +2406,7 @@ export function isMarkerEvent(parsedTrace: Trace.TraceModel.ParsedTrace, event:
2407
2406
  return true;
2408
2407
  }
2409
2408
 
2410
- if (Trace.Types.Events.isFirstContentfulPaint(event) || Trace.Types.Events.isFirstPaint(event)) {
2409
+ if (Trace.Types.Events.isAnyFirstContentfulPaint(event) || Trace.Types.Events.isFirstPaint(event)) {
2411
2410
  return event.args.frame === parsedTrace.data.Meta.mainFrameId;
2412
2411
  }
2413
2412
 
@@ -37,12 +37,14 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
37
37
  */
38
38
  export const SORT_ORDER_PAGE_LOAD_MARKERS: Readonly<Record<string, number>> = {
39
39
  [Trace.Types.Events.Name.NAVIGATION_START]: 0,
40
- [Trace.Types.Events.Name.MARK_LOAD]: 1,
41
- [Trace.Types.Events.Name.MARK_FCP]: 2,
40
+ [Trace.Types.Events.Name.SOFT_NAVIGATION_START]: 1,
42
41
  [Trace.Types.Events.Name.MARK_FIRST_PAINT]: 2,
43
- [Trace.Types.Events.Name.MARK_DOM_CONTENT]: 3,
44
- [Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 4,
45
- [Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 5,
42
+ [Trace.Types.Events.Name.MARK_FCP]: 3,
43
+ [Trace.Types.Events.Name.MARK_SOFT_FCP]: 4,
44
+ [Trace.Types.Events.Name.MARK_DOM_CONTENT]: 5,
45
+ [Trace.Types.Events.Name.MARK_LOAD]: 6,
46
+ [Trace.Types.Events.Name.MARK_LCP_CANDIDATE]: 7,
47
+ [Trace.Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: 8,
46
48
  };
47
49
 
48
50
  export class TimingsTrackAppender implements TrackAppender {
@@ -436,7 +436,6 @@ function linkifyURL(url: Platform.DevToolsPath.UrlString): HTMLElement {
436
436
  return LegacyComponents.Linkifier.Linkifier.linkifyURL(url, {
437
437
  tabStop: true,
438
438
  showColumnNumber: false,
439
- inlineFrameIndex: 0,
440
439
  maxLength: MAX_URL_LENGTH,
441
440
  });
442
441
  }
@@ -267,7 +267,6 @@ function renderURL(request: Trace.Types.Events.SyntheticNetworkRequest): Lit.Tem
267
267
  const options: LegacyComponents.Linkifier.LinkifyURLOptions = {
268
268
  tabStop: true,
269
269
  showColumnNumber: false,
270
- inlineFrameIndex: 0,
271
270
  maxLength: MAX_URL_LENGTH,
272
271
  };
273
272
  const linkifiedURL = LegacyComponents.Linkifier.Linkifier.linkifyURL(
@@ -439,7 +438,6 @@ function renderInitiatedBy(
439
438
  const options: LegacyComponents.Linkifier.LinkifyOptions = {
440
439
  tabStop: true,
441
440
  showColumnNumber: true,
442
- inlineFrameIndex: 0,
443
441
  };
444
442
  // If we have a stack trace, that is the most reliable way to get the initiator data and display a link to the source.
445
443
  if (hasStackTrace) {
@@ -53,7 +53,6 @@ export class ForcedReflow extends BaseInsightComponent<ForcedReflowInsightModel>
53
53
  callFrame.lineNumber, {
54
54
  columnNumber: callFrame.columnNumber,
55
55
  showColumnNumber: true,
56
- inlineFrameIndex: 0,
57
56
  tabStop: true,
58
57
  });
59
58
 
@@ -39,7 +39,6 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
39
39
  const options = {
40
40
  tabStop: true,
41
41
  showColumnNumber: false,
42
- inlineFrameIndex: 0,
43
42
  maxLength: MAX_URL_LENGTH,
44
43
  };
45
44
  const linkEl = LegacyComponents.Linkifier.Linkifier.linkifyURL(fallbackUrl, options);
@@ -1627,6 +1627,8 @@ export class Overlays extends EventTarget {
1627
1627
  markers: HTMLElement, marker: HTMLElement): void {
1628
1628
  if (Trace.Types.Events.isSoftNavigationStart(event)) {
1629
1629
  name = 'Soft Nav';
1630
+ } else if (Trace.Types.Events.isSoftFirstContentfulPaint(event)) {
1631
+ name = 'Soft FCP';
1630
1632
  } else if (Trace.Types.Events.isSoftLargestContentfulPaintCandidate(event)) {
1631
1633
  name = 'Soft LCP';
1632
1634
  }
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: Internal
3
3
  Version: N/A
4
- Revision: e1605f15bac37245745e5fb8327995ededbe2337
4
+ Revision: e32418f5632b194cc1b5a5a0c0b1510d33edcc15
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE