chrome-devtools-frontend 1.0.1519267 → 1.0.1520535
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.
- package/config/owner/COMMON_OWNERS +1 -2
- package/config/typescript/tsconfig.eslint.json +12 -1
- package/docs/ui_engineering.md +1011 -0
- package/front_end/core/host/GdpClient.ts +26 -5
- package/front_end/core/sdk/NetworkManager.ts +1 -0
- package/front_end/core/sdk/NetworkRequest.ts +10 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -1
- package/front_end/entrypoints/main/main-meta.ts +3 -3
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +50 -48
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +128 -30
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +98 -63
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +36 -21
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +75 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +14 -6
- package/front_end/models/ai_assistance/performance/AIContext.ts +62 -7
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +5 -5
- package/front_end/models/badges/Badge.ts +6 -1
- package/front_end/models/badges/StarterBadge.ts +5 -0
- package/front_end/models/badges/UserBadges.ts +5 -4
- package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -7
- package/front_end/panels/ai_assistance/PatchWidget.ts +17 -55
- package/front_end/panels/ai_assistance/components/ChatView.ts +45 -69
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +47 -1
- package/front_end/panels/ai_assistance/components/chatView.css +13 -1
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/animation/animationTimeline.css +4 -0
- package/front_end/panels/application/preloading/components/PreloadingString.ts +2 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +5 -0
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -1
- package/front_end/panels/console/ConsolePrompt.ts +6 -0
- package/front_end/panels/console/ConsoleView.ts +4 -2
- package/front_end/panels/coverage/CoverageListView.ts +146 -198
- package/front_end/panels/coverage/CoverageView.ts +48 -18
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +2 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +22 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -0
- package/front_end/panels/search/SearchResultsPane.ts +48 -15
- package/front_end/panels/search/SearchView.ts +33 -30
- package/front_end/panels/search/searchView.css +0 -2
- package/front_end/panels/settings/components/SyncSection.ts +4 -4
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +1 -4
- package/front_end/panels/sources/DebuggerPlugin.ts +4 -0
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +0 -8
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -5
- package/front_end/panels/timeline/TimelinePanel.ts +2 -0
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -1
- package/front_end/panels/timeline/components/ExportTraceOptions.ts +56 -4
- package/front_end/panels/timeline/components/exportTraceOptions.css +5 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lighthouse/README.chromium +8 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +4 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +3 -2
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/PipeTransport.ts +15 -17
- package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +1 -1
- package/front_end/tsconfig.json +12 -1
- package/front_end/ui/legacy/InspectorView.ts +86 -13
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
- package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
- package/package.json +1 -1
@@ -771,6 +771,24 @@ export class NetworkRequestNode extends NetworkNode {
|
|
771
771
|
return aScore - bScore || aRequest.identityCompare(bRequest);
|
772
772
|
}
|
773
773
|
|
774
|
+
static IsAdRelatedComparator(a: NetworkNode, b: NetworkNode): number {
|
775
|
+
// TODO(allada) Handle this properly for group nodes.
|
776
|
+
const aRequest = a.requestOrFirstKnownChildRequest();
|
777
|
+
const bRequest = b.requestOrFirstKnownChildRequest();
|
778
|
+
if (!aRequest || !bRequest) {
|
779
|
+
return !aRequest ? -1 : 1;
|
780
|
+
}
|
781
|
+
const aIsAdRelated = aRequest.isAdRelated();
|
782
|
+
const bIsAdRelated = bRequest.isAdRelated();
|
783
|
+
if (aIsAdRelated > bIsAdRelated) {
|
784
|
+
return 1;
|
785
|
+
}
|
786
|
+
if (bIsAdRelated > aIsAdRelated) {
|
787
|
+
return -1;
|
788
|
+
}
|
789
|
+
return aRequest.identityCompare(bRequest);
|
790
|
+
}
|
791
|
+
|
774
792
|
static RequestPropertyComparator(propertyName: string, a: NetworkNode, b: NetworkNode): number {
|
775
793
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
776
794
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -1038,6 +1056,10 @@ export class NetworkRequestNode extends NetworkNode {
|
|
1038
1056
|
this.renderAddressSpaceCell(cell, this.requestInternal.remoteAddressSpace());
|
1039
1057
|
break;
|
1040
1058
|
}
|
1059
|
+
case 'is-ad-related': {
|
1060
|
+
this.setTextAndTitle(cell, this.requestInternal.isAdRelated().toLocaleString());
|
1061
|
+
break;
|
1062
|
+
}
|
1041
1063
|
case 'cookies': {
|
1042
1064
|
this.setTextAndTitle(cell, this.arrayLength(this.requestInternal.includedRequestCookies()));
|
1043
1065
|
break;
|
@@ -148,6 +148,10 @@ const UIStrings = {
|
|
148
148
|
* @description Text in Network Log View Columns of the Network panel
|
149
149
|
*/
|
150
150
|
remoteAddressSpace: 'Remote Address Space',
|
151
|
+
/**
|
152
|
+
* @description Text to show whether a request is ad-related
|
153
|
+
*/
|
154
|
+
isAdRelated: 'Is Ad-Related',
|
151
155
|
} as const;
|
152
156
|
const str_ = i18n.i18n.registerUIStrings('panels/network/NetworkLogViewColumns.ts', UIStrings);
|
153
157
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -1183,6 +1187,11 @@ const DEFAULT_COLUMNS = [
|
|
1183
1187
|
title: i18n.i18n.lockedLazyString('User-Agent'),
|
1184
1188
|
sortingFunction: NetworkRequestNode.RequestHeaderStringComparator.bind(null, 'user-agent'),
|
1185
1189
|
},
|
1190
|
+
{
|
1191
|
+
id: 'is-ad-related',
|
1192
|
+
title: i18nLazyString(UIStrings.isAdRelated),
|
1193
|
+
sortingFunction: NetworkRequestNode.IsAdRelatedComparator,
|
1194
|
+
},
|
1186
1195
|
// This header is a placeholder to let datagrid know that it can be sorted by this column, but never shown.
|
1187
1196
|
{
|
1188
1197
|
id: 'waterfall',
|
@@ -8,6 +8,7 @@ import '../../../ui/components/icon_button/icon_button.js';
|
|
8
8
|
import './ControlButton.js';
|
9
9
|
|
10
10
|
import * as i18n from '../../../core/i18n/i18n.js';
|
11
|
+
import * as Badges from '../../../models/badges/badges.js';
|
11
12
|
import * as Buttons from '../../../ui/components/buttons/buttons.js';
|
12
13
|
import * as Input from '../../../ui/components/input/input.js';
|
13
14
|
import * as Lit from '../../../ui/lit/lit.js';
|
@@ -231,6 +232,7 @@ export class CreateRecordingView extends HTMLElement {
|
|
231
232
|
selectorAttribute,
|
232
233
|
),
|
233
234
|
);
|
235
|
+
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.RECORDER_RECORDING_STARTED);
|
234
236
|
}
|
235
237
|
|
236
238
|
#dispatchRecordingCancelled(): void {
|
@@ -136,16 +136,16 @@ const renderSearchMatches =
|
|
136
136
|
};
|
137
137
|
|
138
138
|
export class SearchResultsPane extends UI.Widget.VBox {
|
139
|
-
|
139
|
+
#searchConfig: Workspace.SearchConfig.SearchConfig|null = null;
|
140
140
|
#searchResults: SearchResult[] = [];
|
141
|
+
#resultsUpdated = false;
|
141
142
|
#expandedResults = new WeakSet<SearchResult>();
|
142
143
|
readonly #searchMatches = new WeakMap<SearchResult, SearchMatch[]>();
|
143
144
|
#view: View;
|
144
145
|
|
145
|
-
constructor(
|
146
|
-
super({useShadowDom: true});
|
146
|
+
constructor(element: HTMLElement|undefined, view: View = DEFAULT_VIEW) {
|
147
|
+
super(element, {useShadowDom: true});
|
147
148
|
this.#view = view;
|
148
|
-
this.#searchConfig = searchConfig;
|
149
149
|
}
|
150
150
|
|
151
151
|
get searchResults(): SearchResult[] {
|
@@ -153,20 +153,33 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
153
153
|
}
|
154
154
|
|
155
155
|
set searchResults(searchResults: SearchResult[]) {
|
156
|
-
this.#searchResults
|
157
|
-
|
158
|
-
for (const searchResult of searchResults) {
|
159
|
-
if (this.#expandedResults.has(searchResult)) {
|
160
|
-
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
161
|
-
}
|
156
|
+
if (this.#searchResults === searchResults) {
|
157
|
+
return;
|
162
158
|
}
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
159
|
+
if (this.#searchResults.length !== searchResults.length) {
|
160
|
+
this.#resultsUpdated = true;
|
161
|
+
} else if (this.#searchResults.length === searchResults.length) {
|
162
|
+
for (let i = 0; i < this.#searchResults.length; ++i) {
|
163
|
+
if (this.#searchResults[i] === searchResults[i]) {
|
164
|
+
continue;
|
165
|
+
}
|
166
|
+
this.#resultsUpdated = true;
|
167
|
+
break;
|
168
168
|
}
|
169
169
|
}
|
170
|
+
if (!this.#resultsUpdated) {
|
171
|
+
return;
|
172
|
+
}
|
173
|
+
this.#searchResults = searchResults;
|
174
|
+
this.requestUpdate();
|
175
|
+
}
|
176
|
+
|
177
|
+
get searchConfig(): Workspace.SearchConfig.SearchConfig|null {
|
178
|
+
return this.#searchConfig;
|
179
|
+
}
|
180
|
+
|
181
|
+
set searchConfig(searchConfig: Workspace.SearchConfig.SearchConfig|null) {
|
182
|
+
this.#searchConfig = searchConfig;
|
170
183
|
this.requestUpdate();
|
171
184
|
}
|
172
185
|
|
@@ -174,6 +187,7 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
174
187
|
for (const searchResult of this.#searchResults) {
|
175
188
|
const startMatchIndex = this.#searchMatches.get(searchResult)?.length ?? 0;
|
176
189
|
this.#appendSearchMatches(searchResult, startMatchIndex, searchResult.matchesCount());
|
190
|
+
this.#expandedResults.add(searchResult);
|
177
191
|
}
|
178
192
|
this.requestUpdate();
|
179
193
|
}
|
@@ -190,6 +204,9 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
190
204
|
}
|
191
205
|
|
192
206
|
#appendSearchMatches(searchResult: SearchResult, fromIndex: number, toIndex: number): void {
|
207
|
+
if (!this.#searchConfig) {
|
208
|
+
return;
|
209
|
+
}
|
193
210
|
const queries = this.#searchConfig.queries();
|
194
211
|
const regexes = [];
|
195
212
|
for (let i = 0; i < queries.length; ++i) {
|
@@ -230,6 +247,22 @@ export class SearchResultsPane extends UI.Widget.VBox {
|
|
230
247
|
}
|
231
248
|
|
232
249
|
override performUpdate(): void {
|
250
|
+
if (this.#resultsUpdated) {
|
251
|
+
let matchesExpandedCount = 0;
|
252
|
+
for (const searchResult of this.#searchResults) {
|
253
|
+
if (this.#expandedResults.has(searchResult)) {
|
254
|
+
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
for (const searchResult of this.#searchResults) {
|
258
|
+
if (matchesExpandedCount < matchesExpandedByDefault && !this.#expandedResults.has(searchResult)) {
|
259
|
+
this.#expandedResults.add(searchResult);
|
260
|
+
this.#onExpandSearchResult(searchResult);
|
261
|
+
matchesExpandedCount += this.#searchMatches.get(searchResult)?.length ?? 0;
|
262
|
+
}
|
263
|
+
}
|
264
|
+
this.#resultsUpdated = false;
|
265
|
+
}
|
233
266
|
this.#view(
|
234
267
|
{
|
235
268
|
results: this.#searchResults,
|
@@ -107,15 +107,16 @@ const UIStrings = {
|
|
107
107
|
const str_ = i18n.i18n.registerUIStrings('panels/search/SearchView.ts', UIStrings);
|
108
108
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
109
109
|
const {ref, live} = Directives;
|
110
|
-
const {widgetConfig} = UI.Widget;
|
110
|
+
const {widgetConfig, widgetRef} = UI.Widget;
|
111
111
|
|
112
|
-
interface SearchViewInput {
|
112
|
+
export interface SearchViewInput {
|
113
113
|
query: string;
|
114
114
|
matchCase: boolean;
|
115
115
|
isRegex: boolean;
|
116
|
+
searchConfig: Workspace.SearchConfig.SearchConfig|null;
|
116
117
|
searchMessage: string;
|
117
118
|
searchResultsMessage: string;
|
118
|
-
|
119
|
+
searchResults: SearchResult[];
|
119
120
|
progress: Common.Progress.Progress|null;
|
120
121
|
onQueryChange: (query: string) => void;
|
121
122
|
onQueryKeyDown: (evt: KeyboardEvent) => void;
|
@@ -127,19 +128,22 @@ interface SearchViewInput {
|
|
127
128
|
onClearSearch: () => void;
|
128
129
|
}
|
129
130
|
|
130
|
-
interface SearchViewOutput {
|
131
|
+
export interface SearchViewOutput {
|
131
132
|
focusSearchInput: () => void;
|
133
|
+
showAllMatches: () => void;
|
134
|
+
collapseAllResults: () => void;
|
132
135
|
}
|
133
136
|
|
134
|
-
type View = (input: SearchViewInput, output: SearchViewOutput, target: HTMLElement) => void;
|
137
|
+
export type View = (input: SearchViewInput, output: SearchViewOutput, target: HTMLElement) => void;
|
135
138
|
|
136
139
|
export const DEFAULT_VIEW: View = (input, output, target) => {
|
137
140
|
const {
|
138
141
|
query,
|
139
142
|
matchCase,
|
140
143
|
isRegex,
|
144
|
+
searchConfig,
|
141
145
|
searchMessage,
|
142
|
-
|
146
|
+
searchResults,
|
143
147
|
searchResultsMessage,
|
144
148
|
progress,
|
145
149
|
onQueryChange,
|
@@ -159,12 +163,13 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
159
163
|
{PH1: UI.KeyboardShortcut.KeyboardShortcut.shortcutToString(UI.KeyboardShortcut.Keys.Enter)});
|
160
164
|
} else if (progress) {
|
161
165
|
header = i18nString(UIStrings.searching);
|
162
|
-
} else if (!
|
166
|
+
} else if (!searchResults.length) {
|
163
167
|
header = i18nString(UIStrings.noMatchesFound);
|
164
168
|
text = i18nString(UIStrings.nothingMatchedTheQuery);
|
165
169
|
}
|
166
170
|
// clang-format off
|
167
171
|
render(html`
|
172
|
+
<style>${UI.inspectorCommonStyles}</style>
|
168
173
|
<style>${searchViewStyles}</style>
|
169
174
|
<div class="search-drawer-header" @keydown=${onPanelKeyDown}>
|
170
175
|
<div class="search-container">
|
@@ -240,9 +245,11 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
240
245
|
</devtools-toolbar>
|
241
246
|
</div>
|
242
247
|
<div class="search-results" @keydown=${onPanelKeyDown}>
|
243
|
-
${
|
244
|
-
? html`<devtools-widget .widgetConfig=${widgetConfig(
|
245
|
-
|
248
|
+
${searchResults.length
|
249
|
+
? html`<devtools-widget .widgetConfig=${widgetConfig(SearchResultsPane, {searchResults, searchConfig})}
|
250
|
+
${widgetRef(SearchResultsPane, w => {
|
251
|
+
output.showAllMatches = () => void w.showAllMatches();
|
252
|
+
output.collapseAllResults = () => void w.collapseAllResults(); })}>
|
246
253
|
</devtools-widget>`
|
247
254
|
: html`<devtools-widget .widgetConfig=${widgetConfig(UI.EmptyWidget.EmptyWidget, {header, text})}>
|
248
255
|
</devtools-widget>`}
|
@@ -263,6 +270,8 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
|
|
263
270
|
export class SearchView extends UI.Widget.VBox {
|
264
271
|
readonly #view: View;
|
265
272
|
#focusSearchInput = (): void => {};
|
273
|
+
#showAllMatches = (): void => {};
|
274
|
+
#collapseAllResults = (): void => {};
|
266
275
|
#isIndexing: boolean;
|
267
276
|
#searchId: number;
|
268
277
|
#searchMatchesCount: number;
|
@@ -271,7 +280,6 @@ export class SearchView extends UI.Widget.VBox {
|
|
271
280
|
#searchingView: UI.Widget.Widget|null;
|
272
281
|
#searchConfig: Workspace.SearchConfig.SearchConfig|null;
|
273
282
|
#pendingSearchConfig: Workspace.SearchConfig.SearchConfig|null;
|
274
|
-
#searchResultsPane: SearchResultsPane|null;
|
275
283
|
#progress: Common.Progress.Progress|null;
|
276
284
|
#query: string;
|
277
285
|
#matchCase = false;
|
@@ -307,7 +315,6 @@ export class SearchView extends UI.Widget.VBox {
|
|
307
315
|
this.#searchingView = null;
|
308
316
|
this.#searchConfig = null;
|
309
317
|
this.#pendingSearchConfig = null;
|
310
|
-
this.#searchResultsPane = null;
|
311
318
|
this.#progress = null;
|
312
319
|
this.#throttler = throttler;
|
313
320
|
|
@@ -325,8 +332,9 @@ export class SearchView extends UI.Widget.VBox {
|
|
325
332
|
query: this.#query,
|
326
333
|
matchCase: this.#matchCase,
|
327
334
|
isRegex: this.#isRegex,
|
335
|
+
searchConfig: this.#searchConfig,
|
328
336
|
searchMessage: this.#searchMessage,
|
329
|
-
|
337
|
+
searchResults: this.#searchResults.filter(searchResult => searchResult.matchesCount()),
|
330
338
|
searchResultsMessage: this.#searchResultsMessage,
|
331
339
|
progress: this.#progress,
|
332
340
|
onQueryChange: (query: string) => {
|
@@ -344,6 +352,12 @@ export class SearchView extends UI.Widget.VBox {
|
|
344
352
|
const output: SearchViewOutput = {
|
345
353
|
set focusSearchInput(value: () => void) {
|
346
354
|
that.#focusSearchInput = value;
|
355
|
+
},
|
356
|
+
set showAllMatches(value: () => void) {
|
357
|
+
that.#showAllMatches = value;
|
358
|
+
},
|
359
|
+
set collapseAllResults(value: () => void) {
|
360
|
+
that.#collapseAllResults = value;
|
347
361
|
}
|
348
362
|
};
|
349
363
|
this.#view(input, output, this.contentElement);
|
@@ -436,17 +450,10 @@ export class SearchView extends UI.Widget.VBox {
|
|
436
450
|
this.#onIndexingFinished();
|
437
451
|
return;
|
438
452
|
}
|
439
|
-
if (!this.#searchResultsPane) {
|
440
|
-
this.#searchResultsPane = this.createSearchResultsPane();
|
441
|
-
}
|
442
453
|
this.#searchResults.push(searchResult);
|
443
454
|
void this.#throttler.schedule(async () => this.#setSearchResults());
|
444
455
|
}
|
445
456
|
|
446
|
-
protected createSearchResultsPane(): SearchResultsPane {
|
447
|
-
return new SearchResultsPane((this.#searchConfig as Workspace.SearchConfig.SearchConfig));
|
448
|
-
}
|
449
|
-
|
450
457
|
#setSearchResults(): void {
|
451
458
|
this.#searchMatchesCount = 0;
|
452
459
|
this.#searchResultsCount = 0;
|
@@ -454,9 +461,7 @@ export class SearchView extends UI.Widget.VBox {
|
|
454
461
|
for (const searchResult of this.#searchResults) {
|
455
462
|
this.#addSearchResult(searchResult);
|
456
463
|
}
|
457
|
-
|
458
|
-
this.#searchResultsPane.searchResults = this.#searchResults.filter(searchResult => searchResult.matchesCount());
|
459
|
-
}
|
464
|
+
this.performUpdate();
|
460
465
|
}
|
461
466
|
|
462
467
|
#onSearchFinished(searchId: number, finished: boolean): void {
|
@@ -465,7 +470,6 @@ export class SearchView extends UI.Widget.VBox {
|
|
465
470
|
}
|
466
471
|
this.#progress = null;
|
467
472
|
this.#searchFinished(finished);
|
468
|
-
this.#searchConfig = null;
|
469
473
|
UI.ARIAUtils.LiveAnnouncer.alert(this.#searchMessage + ' ' + this.#searchResultsMessage);
|
470
474
|
}
|
471
475
|
|
@@ -486,7 +490,7 @@ export class SearchView extends UI.Widget.VBox {
|
|
486
490
|
|
487
491
|
#resetSearch(): void {
|
488
492
|
this.#stopSearch();
|
489
|
-
this.#
|
493
|
+
this.#searchResults = [];
|
490
494
|
this.#searchMessage = '';
|
491
495
|
this.#searchResultsMessage = '';
|
492
496
|
this.performUpdate();
|
@@ -499,7 +503,6 @@ export class SearchView extends UI.Widget.VBox {
|
|
499
503
|
if (this.#searchScope) {
|
500
504
|
this.#searchScope.stopSearch();
|
501
505
|
}
|
502
|
-
this.#searchConfig = null;
|
503
506
|
}
|
504
507
|
|
505
508
|
#searchStarted(): void {
|
@@ -544,7 +547,7 @@ export class SearchView extends UI.Widget.VBox {
|
|
544
547
|
|
545
548
|
#searchFinished(finished: boolean): void {
|
546
549
|
this.#searchMessage = finished ? i18nString(UIStrings.searchFinished) : i18nString(UIStrings.searchInterrupted);
|
547
|
-
this.
|
550
|
+
this.requestUpdate();
|
548
551
|
}
|
549
552
|
|
550
553
|
override focus(): void {
|
@@ -593,15 +596,15 @@ export class SearchView extends UI.Widget.VBox {
|
|
593
596
|
// "Command + Alt + [" for Mac
|
594
597
|
const shouldCollapseAllForMac =
|
595
598
|
isMac && event.metaKey && !event.ctrlKey && event.altKey && event.code === 'BracketLeft';
|
596
|
-
// "
|
599
|
+
// "Ctrl + Alt + {" for other platforms
|
597
600
|
const shouldCollapseAllForOtherPlatforms =
|
598
601
|
!isMac && event.ctrlKey && !event.metaKey && event.shiftKey && event.code === 'BracketLeft';
|
599
602
|
|
600
603
|
if (shouldShowAllForMac || shouldShowAllForOtherPlatforms) {
|
601
|
-
this.#
|
604
|
+
this.#showAllMatches();
|
602
605
|
void VisualLogging.logKeyDown(event.currentTarget, event, 'show-all-matches');
|
603
606
|
} else if (shouldCollapseAllForMac || shouldCollapseAllForOtherPlatforms) {
|
604
|
-
this.#
|
607
|
+
this.#collapseAllResults();
|
605
608
|
void VisualLogging.logKeyDown(event.currentTarget, event, 'collapse-all-results');
|
606
609
|
}
|
607
610
|
}
|
@@ -5,7 +5,6 @@
|
|
5
5
|
*/
|
6
6
|
|
7
7
|
.search-drawer-header {
|
8
|
-
align-items: center;
|
9
8
|
flex-shrink: 0;
|
10
9
|
overflow: hidden;
|
11
10
|
display: inline-flex;
|
@@ -14,7 +13,6 @@
|
|
14
13
|
.search-container {
|
15
14
|
border-bottom: 1px solid var(--sys-color-divider);
|
16
15
|
display: flex;
|
17
|
-
height: 100%;
|
18
16
|
align-items: center;
|
19
17
|
flex-grow: 1;
|
20
18
|
}
|
@@ -31,10 +31,10 @@ const UIStrings = {
|
|
31
31
|
*/
|
32
32
|
syncDisabled: 'To turn this setting on, you must enable Chrome sync.',
|
33
33
|
/**
|
34
|
-
* @description Text shown to the user in the Settings UI.
|
35
|
-
* to
|
34
|
+
* @description Text shown to the user in the Settings UI. Explains why the checkbox
|
35
|
+
* for saving DevTools settings to the user's Google account is inactive.
|
36
36
|
*/
|
37
|
-
preferencesSyncDisabled: '
|
37
|
+
preferencesSyncDisabled: 'You need to first enable saving `Chrome` settings in your `Google` account.',
|
38
38
|
/**
|
39
39
|
* @description Label for the account email address. Shown in the DevTools Settings UI in
|
40
40
|
* front of the email address currently used for Chrome Sync.
|
@@ -270,7 +270,7 @@ function renderWarningIfNeeded(syncInfo: Host.InspectorFrontendHostAPI.SyncInfor
|
|
270
270
|
return html`
|
271
271
|
<devtools-button
|
272
272
|
aria-describedby=settings-sync-info
|
273
|
-
|
273
|
+
.title=${warningText}
|
274
274
|
.iconName=${'info'}
|
275
275
|
.variant=${Buttons.Button.Variant.ICON}
|
276
276
|
.size=${Buttons.Button.Size.SMALL}
|
@@ -103,6 +103,7 @@ export class AiCodeCompletionPlugin extends Plugin {
|
|
103
103
|
if (this.#teaser) {
|
104
104
|
if (update.docChanged) {
|
105
105
|
update.view.dispatch({effects: this.#teaserCompartment.reconfigure([])});
|
106
|
+
window.clearTimeout(this.#teaserDisplayTimeout);
|
106
107
|
this.#addTeaserPluginToCompartment(update.view);
|
107
108
|
} else if (update.selectionSet && update.state.doc.length > 0) {
|
108
109
|
update.view.dispatch({effects: this.#teaserCompartment.reconfigure([])});
|
@@ -187,10 +188,6 @@ export class AiCodeCompletionPlugin extends Plugin {
|
|
187
188
|
}
|
188
189
|
|
189
190
|
#addTeaserPluginToCompartment = Common.Debouncer.debounce((view: CodeMirror.EditorView) => {
|
190
|
-
if (this.#teaserDisplayTimeout) {
|
191
|
-
window.clearTimeout(this.#teaserDisplayTimeout);
|
192
|
-
this.#teaserDisplayTimeout = undefined;
|
193
|
-
}
|
194
191
|
this.#teaserDisplayTimeout = window.setTimeout(() => {
|
195
192
|
this.#addTeaserPluginToCompartmentImmediate(view);
|
196
193
|
}, AiCodeCompletion.AiCodeCompletion.DELAY_BEFORE_SHOWING_RESPONSE_MS);
|
@@ -10,6 +10,7 @@ import * as i18n from '../../core/i18n/i18n.js';
|
|
10
10
|
import * as Platform from '../../core/platform/platform.js';
|
11
11
|
import * as SDK from '../../core/sdk/sdk.js';
|
12
12
|
import * as Protocol from '../../generated/protocol.js';
|
13
|
+
import * as Badges from '../../models/badges/badges.js';
|
13
14
|
import * as Bindings from '../../models/bindings/bindings.js';
|
14
15
|
import * as Breakpoints from '../../models/breakpoints/breakpoints.js';
|
15
16
|
import * as Formatter from '../../models/formatter/formatter.js';
|
@@ -1628,6 +1629,9 @@ export class DebuggerPlugin extends Plugin {
|
|
1628
1629
|
this.uiSourceCode, lineNumber, columnNumber, condition, enabled, isLogpoint,
|
1629
1630
|
Breakpoints.BreakpointManager.BreakpointOrigin.USER_ACTION);
|
1630
1631
|
this.breakpointWasSetForTest(lineNumber, columnNumber, condition, enabled);
|
1632
|
+
if (bp) {
|
1633
|
+
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.BREAKPOINT_ADDED);
|
1634
|
+
}
|
1631
1635
|
return bp;
|
1632
1636
|
}
|
1633
1637
|
|
@@ -226,7 +226,7 @@ export class ThirdPartyTreeViewWidget extends TimelineTreeView.TimelineTreeView
|
|
226
226
|
const unattributed = i18nString(UIStrings.unattributed);
|
227
227
|
const id = typeof node.id === 'symbol' ? undefined : node.id;
|
228
228
|
// This `undefined` is [unattributed]
|
229
|
-
// TODO(paulirish
|
229
|
+
// TODO(paulirish): Improve attribution to reduce amount of items in [unattributed].
|
230
230
|
const domainName = id ? this.entityMapper()?.entityForEvent(node.event)?.name || id : undefined;
|
231
231
|
return {name: domainName || unattributed, color, icon: undefined};
|
232
232
|
}
|
@@ -254,14 +254,6 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
254
254
|
if (perfAIEntryPointEnabled && this.parsedTrace) {
|
255
255
|
const callTree = AIAssistance.AICallTree.fromEvent(entry, this.parsedTrace);
|
256
256
|
if (callTree) {
|
257
|
-
let focus = UI.Context.Context.instance().flavor(AIAssistance.AgentFocus);
|
258
|
-
if (focus) {
|
259
|
-
focus = focus.withCallTree(callTree);
|
260
|
-
} else {
|
261
|
-
focus = AIAssistance.AgentFocus.fromCallTree(callTree);
|
262
|
-
}
|
263
|
-
UI.Context.Context.instance().setFlavor(AIAssistance.AgentFocus, focus);
|
264
|
-
|
265
257
|
const action = UI.ActionRegistry.ActionRegistry.instance().getAction(PERF_AI_ACTION_ID);
|
266
258
|
|
267
259
|
if (Root.Runtime.hostConfig.devToolsAiSubmenuPrompts?.enabled) {
|
@@ -1516,13 +1516,13 @@ export class TimelineFlameChartView extends Common.ObjectWrapper.eventMixin<Even
|
|
1516
1516
|
return;
|
1517
1517
|
}
|
1518
1518
|
|
1519
|
-
const
|
1520
|
-
|
1519
|
+
const event = selectionIsEvent(selection) ? selection.event : null;
|
1520
|
+
|
1521
1521
|
let focus = UI.Context.Context.instance().flavor(AIAssistance.AgentFocus);
|
1522
1522
|
if (focus) {
|
1523
|
-
focus = focus.
|
1524
|
-
} else if (
|
1525
|
-
focus = AIAssistance.AgentFocus.
|
1523
|
+
focus = focus.withEvent(event);
|
1524
|
+
} else if (event) {
|
1525
|
+
focus = AIAssistance.AgentFocus.fromEvent(this.#parsedTrace, event);
|
1526
1526
|
} else {
|
1527
1527
|
focus = null;
|
1528
1528
|
}
|
@@ -44,6 +44,7 @@ import * as Root from '../../core/root/root.js';
|
|
44
44
|
import * as SDK from '../../core/sdk/sdk.js';
|
45
45
|
import type * as Protocol from '../../generated/protocol.js';
|
46
46
|
import * as AiAssistanceModel from '../../models/ai_assistance/ai_assistance.js';
|
47
|
+
import * as Badges from '../../models/badges/badges.js';
|
47
48
|
import * as CrUXManager from '../../models/crux-manager/crux-manager.js';
|
48
49
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
49
50
|
import * as Trace from '../../models/trace/trace.js';
|
@@ -1924,6 +1925,7 @@ export class TimelinePanel extends Common.ObjectWrapper.eventMixin<EventTypes, t
|
|
1924
1925
|
} else {
|
1925
1926
|
await this.#startTraceRecording();
|
1926
1927
|
}
|
1928
|
+
Badges.UserBadges.instance().recordAction(Badges.BadgeAction.PERFORMANCE_RECORDING_STARTED);
|
1927
1929
|
}
|
1928
1930
|
|
1929
1931
|
private async stopRecording(): Promise<void> {
|
@@ -1005,7 +1005,7 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
|
|
1005
1005
|
case AggregatedTimelineTreeView.GroupBy.Subdomain:
|
1006
1006
|
case AggregatedTimelineTreeView.GroupBy.ThirdParties: {
|
1007
1007
|
// This `undefined` is [unattributed]
|
1008
|
-
// TODO(paulirish
|
1008
|
+
// TODO(paulirish): Improve attribution to reduce amount of items in [unattributed].
|
1009
1009
|
const domainName = id ? this.beautifyDomainName(id, node) : undefined;
|
1010
1010
|
return {name: domainName || unattributed, color, icon: undefined};
|
1011
1011
|
}
|
@@ -3,6 +3,9 @@
|
|
3
3
|
// found in the LICENSE file.
|
4
4
|
/* eslint-disable rulesdir/no-lit-render-outside-of-view */
|
5
5
|
|
6
|
+
import '../../../ui/components/tooltips/tooltips.js';
|
7
|
+
import '../../../ui/components/buttons/buttons.js';
|
8
|
+
|
6
9
|
import * as Common from '../../../core/common/common.js';
|
7
10
|
import * as Host from '../../../core/host/host.js';
|
8
11
|
import * as i18n from '../../../core/i18n/i18n.js';
|
@@ -46,6 +49,18 @@ const UIStrings = {
|
|
46
49
|
* @description Text for the save trace button
|
47
50
|
*/
|
48
51
|
saveButtonTitle: 'Save',
|
52
|
+
/**
|
53
|
+
* @description Title for the information icon showing more information about an option
|
54
|
+
*/
|
55
|
+
moreInfoTitle: 'More information',
|
56
|
+
/**
|
57
|
+
* @description Text shown in the information pop-up next to the "Include script content" option.
|
58
|
+
*/
|
59
|
+
scriptContentPrivacyInfo: 'Includes the full content of all loaded scripts (except extensions).',
|
60
|
+
/**
|
61
|
+
* @description Text shown in the information pop-up next to the "Include script sourcemaps" option.
|
62
|
+
*/
|
63
|
+
sourceMapsContentPrivacyInfo: 'Includes available source maps, which may expose authored code.'
|
49
64
|
} as const;
|
50
65
|
|
51
66
|
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/ExportTraceOptions.ts', UIStrings);
|
@@ -74,6 +89,9 @@ export interface ExportTraceOptionsState {
|
|
74
89
|
displaySourceMapsCheckbox?: boolean;
|
75
90
|
}
|
76
91
|
|
92
|
+
type CheckboxId = 'annotations'|'script-content'|'script-source-maps'|'compress-with-gzip';
|
93
|
+
const checkboxesWithInfoDialog = new Set<CheckboxId>(['script-content', 'script-source-maps']);
|
94
|
+
|
77
95
|
export class ExportTraceOptions extends HTMLElement {
|
78
96
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
79
97
|
#data: ExportTraceOptionsData|null = null;
|
@@ -187,7 +205,7 @@ export class ExportTraceOptions extends HTMLElement {
|
|
187
205
|
}
|
188
206
|
|
189
207
|
#renderCheckbox(
|
190
|
-
checkboxWithLabel: UI.UIUtils.CheckboxLabel, title: Common.UIString.LocalizedString,
|
208
|
+
checkboxId: CheckboxId, checkboxWithLabel: UI.UIUtils.CheckboxLabel, title: Common.UIString.LocalizedString,
|
191
209
|
checked: boolean): Lit.TemplateResult {
|
192
210
|
UI.Tooltip.Tooltip.install(checkboxWithLabel, title);
|
193
211
|
checkboxWithLabel.ariaLabel = title;
|
@@ -202,11 +220,40 @@ export class ExportTraceOptions extends HTMLElement {
|
|
202
220
|
return html`
|
203
221
|
<div class='export-trace-options-row'>
|
204
222
|
${checkboxWithLabel}
|
223
|
+
|
224
|
+
${checkboxesWithInfoDialog.has(checkboxId) ? html`
|
225
|
+
<devtools-button
|
226
|
+
aria-details=${`export-trace-tooltip-${checkboxId}`}
|
227
|
+
class="pen-icon"
|
228
|
+
.title=${UIStrings.moreInfoTitle}
|
229
|
+
.iconName=${'info'}
|
230
|
+
.variant=${Buttons.Button.Variant.ICON}
|
231
|
+
></devtools-button>
|
232
|
+
` : Lit.nothing}
|
205
233
|
</div>
|
206
234
|
`;
|
207
235
|
// clang-format on
|
208
236
|
}
|
209
237
|
|
238
|
+
#renderInfoTooltip(checkboxId: CheckboxId): Lit.LitTemplate {
|
239
|
+
if (!checkboxesWithInfoDialog.has(checkboxId)) {
|
240
|
+
return Lit.nothing;
|
241
|
+
}
|
242
|
+
|
243
|
+
return html`
|
244
|
+
<devtools-tooltip
|
245
|
+
variant="rich"
|
246
|
+
id=${`export-trace-tooltip-${checkboxId}`}
|
247
|
+
>
|
248
|
+
<div class="info-tooltip-container">
|
249
|
+
<p>
|
250
|
+
${checkboxId === 'script-content' ? i18nString(UIStrings.scriptContentPrivacyInfo) : Lit.nothing}
|
251
|
+
${checkboxId === 'script-source-maps' ? i18nString(UIStrings.sourceMapsContentPrivacyInfo) : Lit.nothing}
|
252
|
+
</p>
|
253
|
+
</div>
|
254
|
+
</devtools-tooltip>`;
|
255
|
+
}
|
256
|
+
|
210
257
|
#render(): void {
|
211
258
|
if (!ComponentHelpers.ScheduledRender.isScheduledRender(this)) {
|
212
259
|
throw new Error('Export trace options dialog render was not scheduled');
|
@@ -230,16 +277,18 @@ export class ExportTraceOptions extends HTMLElement {
|
|
230
277
|
state: this.#state.dialogState,
|
231
278
|
} as Dialogs.ButtonDialog.ButtonDialogData}>
|
232
279
|
<div class='export-trace-options-content'>
|
233
|
-
${this.#state.displayAnnotationsCheckbox ? this.#renderCheckbox(this.#includeAnnotationsCheckbox,
|
280
|
+
${this.#state.displayAnnotationsCheckbox ? this.#renderCheckbox('annotations', this.#includeAnnotationsCheckbox,
|
234
281
|
i18nString(UIStrings.includeAnnotations),
|
235
282
|
this.#state.includeAnnotations): ''}
|
236
|
-
${this.#state.displayScriptContentCheckbox ? this.#renderCheckbox(this.#includeScriptContentCheckbox,
|
283
|
+
${this.#state.displayScriptContentCheckbox ? this.#renderCheckbox('script-content', this.#includeScriptContentCheckbox,
|
237
284
|
i18nString(UIStrings.includeScriptContent), this.#state.includeScriptContent): ''}
|
238
285
|
${this.#state.displayScriptContentCheckbox && this.#state.displaySourceMapsCheckbox ? this.#renderCheckbox(
|
286
|
+
'script-source-maps',
|
239
287
|
this.#includeSourceMapsCheckbox, i18nString(UIStrings.includeSourcemap), this.#state.includeSourceMaps): ''}
|
240
|
-
${this.#renderCheckbox(this.#shouldCompressCheckbox, i18nString(UIStrings.shouldCompress), this.#state.shouldCompress)}
|
288
|
+
${this.#renderCheckbox('compress-with-gzip', this.#shouldCompressCheckbox, i18nString(UIStrings.shouldCompress), this.#state.shouldCompress)}
|
241
289
|
<div class='export-trace-options-row'><div class='export-trace-blank'></div><devtools-button
|
242
290
|
class="setup-button"
|
291
|
+
data-export-button
|
243
292
|
@click=${this.#onExportClick.bind(this)}
|
244
293
|
.data=${{
|
245
294
|
variant: Buttons.Button.Variant.PRIMARY,
|
@@ -249,6 +298,9 @@ export class ExportTraceOptions extends HTMLElement {
|
|
249
298
|
</div>
|
250
299
|
</div>
|
251
300
|
</devtools-button-dialog>
|
301
|
+
|
302
|
+
${this.#state.displayScriptContentCheckbox ? this.#renderInfoTooltip('script-content') : Lit.nothing}
|
303
|
+
${this.#state.displayScriptContentCheckbox && this.#state.displaySourceMapsCheckbox ? this.#renderInfoTooltip('script-source-maps') : Lit.nothing}
|
252
304
|
`;
|
253
305
|
// clang-format on
|
254
306
|
Lit.render(output, this.#shadow, {host: this});
|