chrome-devtools-frontend 1.0.1515446 → 1.0.1515796

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/front_end/entrypoints/main/main-meta.ts +2 -2
  2. package/front_end/generated/InspectorBackendCommands.js +4 -4
  3. package/front_end/generated/SupportedCSSProperties.js +12 -0
  4. package/front_end/generated/protocol.ts +10 -1
  5. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +64 -0
  6. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +78 -58
  7. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +123 -55
  8. package/front_end/models/javascript_metadata/NativeFunctions.js +7 -7
  9. package/front_end/models/text_utils/TextUtils.ts +26 -0
  10. package/front_end/models/trace/Processor.ts +1 -1
  11. package/front_end/models/trace/insights/DocumentLatency.ts +9 -7
  12. package/front_end/models/trace/types/Configuration.ts +12 -0
  13. package/front_end/panels/application/components/BackForwardCacheStrings.ts +8 -2
  14. package/front_end/panels/common/BadgeNotification.ts +10 -8
  15. package/front_end/panels/common/GdpSignUpDialog.ts +24 -11
  16. package/front_end/panels/common/gdpSignUpDialog.css +4 -0
  17. package/front_end/panels/search/SearchView.ts +195 -135
  18. package/front_end/panels/settings/components/SyncSection.ts +58 -9
  19. package/front_end/panels/settings/components/syncSection.css +6 -0
  20. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +1 -4
  21. package/front_end/panels/webauthn/WebauthnPane.ts +1 -1
  22. package/front_end/third_party/chromium/README.chromium +1 -1
  23. package/front_end/third_party/puppeteer/README.chromium +2 -2
  24. package/front_end/third_party/puppeteer/package/README.md +6 -3
  25. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +1 -1
  26. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +11 -1
  27. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  28. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js +2 -2
  29. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  30. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +5 -1
  31. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  32. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +30 -8
  33. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  34. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  35. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +1 -3
  36. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  37. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
  38. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts +1 -1
  39. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  40. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +8 -2
  41. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +1 -1
  42. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +5 -1
  43. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  44. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +8 -2
  45. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  46. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
  47. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
  48. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  49. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  50. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +5 -0
  51. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
  52. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  53. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +12 -2
  54. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +22 -8
  55. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +1 -1
  56. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +11 -1
  57. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  58. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js +2 -2
  59. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  60. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +5 -1
  61. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  62. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +30 -8
  63. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +1 -3
  66. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +8 -2
  70. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
  71. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +5 -1
  72. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  73. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +8 -2
  74. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  75. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
  76. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +5 -0
  79. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/types.d.ts +12 -2
  81. package/front_end/third_party/puppeteer/package/package.json +4 -4
  82. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +1 -1
  83. package/front_end/third_party/puppeteer/package/src/api/Page.ts +13 -2
  84. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +50 -8
  85. package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +0 -1
  86. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +8 -1
  87. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +21 -5
  88. package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
  89. package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +12 -0
  90. package/front_end/ui/components/text_editor/config.ts +66 -16
  91. package/front_end/ui/legacy/ProgressIndicator.ts +4 -5
  92. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +4 -2
  93. package/front_end/ui/visual_logging/Debugging.ts +24 -12
  94. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  95. package/package.json +3 -3
@@ -108,67 +108,51 @@ const str_ = i18n.i18n.registerUIStrings('panels/search/SearchView.ts', UIString
108
108
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
109
109
  const {ref} = Directives;
110
110
 
111
- export class SearchView extends UI.Widget.VBox {
112
- #focusOnShow: boolean;
113
- #isIndexing: boolean;
114
- #searchId: number;
115
- #searchMatchesCount: number;
116
- #searchResultsCount: number;
117
- #nonEmptySearchResultsCount: number;
118
- #searchingView: UI.Widget.Widget|null;
119
- #notFoundView: UI.Widget.Widget|null;
120
- #searchConfig: Workspace.SearchConfig.SearchConfig|null;
121
- #pendingSearchConfig: Workspace.SearchConfig.SearchConfig|null;
122
- #searchResultsPane: SearchResultsPane|null;
123
- #progressIndicator: UI.ProgressIndicator.ProgressIndicator|null;
124
- #visiblePane: UI.Widget.Widget|null;
125
- #searchResultsElement!: HTMLElement;
126
- #searchInputElement!: HTMLInputElement;
127
- #matchCaseButton!: Buttons.Button.Button;
128
- #regexButton!: Buttons.Button.Button;
129
- #searchMessageElement!: HTMLElement;
130
- #searchProgressPlaceholderElement!: HTMLElement;
131
- #searchResultsMessageElement!: HTMLElement;
132
- readonly #advancedSearchConfig: Common.Settings.Setting<{
133
- query: string,
134
- ignoreCase: boolean,
135
- isRegex: boolean,
136
- }>;
137
- #searchScope: SearchScope|null;
138
-
139
- // We throttle adding search results, otherwise we trigger DOM layout for each
140
- // result added.
141
- #throttler: Common.Throttler.Throttler;
142
- #pendingSearchResults: SearchResult[] = [];
143
- #emptyStartView: UI.EmptyWidget.EmptyWidget;
144
-
145
- constructor(settingKey: string, throttler: Common.Throttler.Throttler) {
146
- super({
147
- jslog: `${VisualLogging.panel('search').track({resize: true})}`,
148
- useShadowDom: true,
149
- });
150
- this.setMinimumSize(0, 40);
111
+ interface SearchViewInput {
112
+ query: string;
113
+ focusSearchInput: boolean;
114
+ matchCase: boolean;
115
+ isRegex: boolean;
116
+ searchMessage: string;
117
+ searchResultsMessage: string;
118
+ onQueryChange: (query: string) => void;
119
+ onQueryKeyDown: (evt: KeyboardEvent) => void;
120
+ onPanelKeyDown: (evt: KeyboardEvent) => void;
121
+ onClearSearchInput: () => void;
122
+ onToggleRegex: () => void;
123
+ onToggleMatchCase: () => void;
124
+ onRefresh: () => void;
125
+ onClearSearch: () => void;
126
+ }
151
127
 
152
- this.#focusOnShow = false;
153
- this.#isIndexing = false;
154
- this.#searchId = 1;
155
- this.#searchMatchesCount = 0;
156
- this.#searchResultsCount = 0;
157
- this.#nonEmptySearchResultsCount = 0;
158
- this.#searchingView = null;
159
- this.#notFoundView = null;
160
- this.#searchConfig = null;
161
- this.#pendingSearchConfig = null;
162
- this.#searchResultsPane = null;
163
- this.#progressIndicator = null;
164
- this.#visiblePane = null;
165
- this.#throttler = throttler;
128
+ interface SearchViewOutput {
129
+ searchResultsElement?: HTMLElement;
130
+ searchProgressPlaceholderElement?: HTMLElement;
131
+ }
166
132
 
167
- // clang-format off
168
- /* eslint-disable-next-line rulesdir/no-lit-render-outside-of-view */
169
- render(html`
133
+ type View = (input: SearchViewInput, output: SearchViewOutput, target: HTMLElement) => void;
134
+
135
+ export const DEFAULT_VIEW: View = (input, output, target) => {
136
+ const {
137
+ query,
138
+ focusSearchInput,
139
+ matchCase,
140
+ isRegex,
141
+ searchMessage,
142
+ searchResultsMessage,
143
+ onQueryChange,
144
+ onQueryKeyDown,
145
+ onPanelKeyDown,
146
+ onClearSearchInput,
147
+ onToggleRegex,
148
+ onToggleMatchCase,
149
+ onRefresh,
150
+ onClearSearch,
151
+ } = input;
152
+ // clang-format off
153
+ render(html`
170
154
  <style>${searchViewStyles}</style>
171
- <div class="search-drawer-header" @keydown=${this.#onPanelKeyDown}>
155
+ <div class="search-drawer-header" @keydown=${onPanelKeyDown}>
172
156
  <div class="search-container">
173
157
  <div class="toolbar-item-search">
174
158
  <devtools-icon name="search"></devtools-icon>
@@ -179,10 +163,17 @@ export class SearchView extends UI.Widget.VBox {
179
163
  change: true, keydown: 'ArrowUp|ArrowDown|Enter'})}
180
164
  aria-label=${i18nString(UIStrings.find)}
181
165
  size="100" results="0"
182
- @keydown=${this.#onQueryKeyDown}
183
- ${ref(e => {this.#searchInputElement = e as HTMLInputElement;})}>
166
+ .value=${query}
167
+ @keydown=${onQueryKeyDown}
168
+ @input=${(e: Event) => onQueryChange((e.target as HTMLInputElement).value)}
169
+ ${ref(e => {
170
+ if (e instanceof HTMLInputElement && focusSearchInput) {
171
+ e.focus();
172
+ e.select();
173
+ }
174
+ })}>
184
175
  <devtools-button class="clear-button" tabindex="-1"
185
- @click=${this.#onClearSearchInput}
176
+ @click=${onClearSearchInput}
186
177
  .data=${{
187
178
  variant: Buttons.Button.Variant.ICON,
188
179
  iconName: 'cross-circle-filled',
@@ -191,40 +182,40 @@ export class SearchView extends UI.Widget.VBox {
191
182
  title: i18nString(UIStrings.clearInput),
192
183
  } as Buttons.Button.ButtonData}
193
184
  ></devtools-button>
194
- <devtools-button @click=${this.#onToggleRegex} .data=${{
185
+ <devtools-button @click=${onToggleRegex} .data=${{
195
186
  variant: Buttons.Button.Variant.ICON_TOGGLE,
196
187
  iconName: 'regular-expression',
197
188
  toggledIconName: 'regular-expression',
198
189
  toggleType: Buttons.Button.ToggleType.PRIMARY,
199
190
  size: Buttons.Button.Size.SMALL,
200
- toggled: false,
201
- title: i18nString(UIStrings.enableRegularExpression),
191
+ toggled: isRegex,
192
+ title: isRegex ? i18nString(UIStrings.disableRegularExpression) : i18nString(UIStrings.enableRegularExpression),
202
193
  jslogContext: 'regular-expression',
203
194
  } as Buttons.Button.ButtonData}
204
- ${ref(e => {this.#regexButton = e as Buttons.Button.Button;})}
195
+ class="regex-button"
205
196
  ></devtools-button>
206
- <devtools-button @click=${this.#onToggleMatchCase} .data=${{
197
+ <devtools-button @click=${onToggleMatchCase} .data=${{
207
198
  variant: Buttons.Button.Variant.ICON_TOGGLE,
208
199
  iconName: 'match-case',
209
200
  toggledIconName: 'match-case',
210
201
  toggleType: Buttons.Button.ToggleType.PRIMARY,
211
202
  size: Buttons.Button.Size.SMALL,
212
- toggled: false,
213
- title: i18nString(UIStrings.enableCaseSensitive),
203
+ toggled: matchCase,
204
+ title: matchCase ? i18nString(UIStrings.disableCaseSensitive) : i18nString(UIStrings.enableCaseSensitive),
214
205
  jslogContext: 'match-case',
215
206
  } as Buttons.Button.ButtonData}
216
- ${ref(e => {this.#matchCaseButton = e as Buttons.Button.Button;})}
207
+ class="match-case-button"
217
208
  ></devtools-button>
218
209
  </div>
219
210
  </div>
220
211
  <devtools-toolbar class="search-toolbar" jslog=${VisualLogging.toolbar()}>
221
- <devtools-button title=${i18nString(UIStrings.refresh)} @click=${this.#onRefresh}
212
+ <devtools-button title=${i18nString(UIStrings.refresh)} @click=${onRefresh}
222
213
  .data=${{
223
214
  variant: Buttons.Button.Variant.TOOLBAR,
224
215
  iconName: 'refresh',
225
216
  jslogContext: 'search.refresh',
226
217
  } as Buttons.Button.ButtonData}></devtools-button>
227
- <devtools-button title=${i18nString(UIStrings.clear)} @click=${this.#onClearSearch}
218
+ <devtools-button title=${i18nString(UIStrings.clear)} @click=${onClearSearch}
228
219
  .data=${{
229
220
  variant: Buttons.Button.Variant.TOOLBAR,
230
221
  iconName: 'clear',
@@ -232,22 +223,83 @@ export class SearchView extends UI.Widget.VBox {
232
223
  } as Buttons.Button.ButtonData}></devtools-button>
233
224
  </devtools-toolbar>
234
225
  </div>
235
- <div class="search-results" @keydown=${this.#onPanelKeyDown}
236
- ${ref(e => {this.#searchResultsElement = e as HTMLElement;})}>
226
+ <div class="search-results" @keydown=${onPanelKeyDown}
227
+ ${ref(e => {output.searchResultsElement = e as HTMLElement;})}>
237
228
  </div>
238
- <div class="search-toolbar-summary" @keydown=${this.#onPanelKeyDown}>
239
- <div class="search-message" ${ref(e => {this.#searchMessageElement = e as HTMLElement;})}></div>
240
- <div class="flex-centered" ${ref(e => {this.#searchProgressPlaceholderElement = e as HTMLElement;})}>
241
- </div>
242
- <div class="search-message" ${ref(e => {this.#searchResultsMessageElement = e as HTMLElement;})}>
229
+ <div class="search-toolbar-summary" @keydown=${onPanelKeyDown}>
230
+ <div class="search-message">${searchMessage}</div>
231
+ <div class="flex-centered" ${ref(e => {output.searchProgressPlaceholderElement = e as HTMLElement;})}>
243
232
  </div>
244
- </div>`, this.contentElement, {host: this});
245
- // clang-format on
233
+ <div class="search-message">${searchResultsMessage}</div>
234
+ </div>`, target);
235
+ // clang-format on
236
+ };
237
+
238
+ export class SearchView extends UI.Widget.VBox {
239
+ readonly #view: View;
240
+ #focusSearchInput: boolean;
241
+ #isIndexing: boolean;
242
+ #searchId: number;
243
+ #searchMatchesCount: number;
244
+ #searchResultsCount: number;
245
+ #nonEmptySearchResultsCount: number;
246
+ #searchingView: UI.Widget.Widget|null;
247
+ #notFoundView: UI.Widget.Widget|null;
248
+ #searchConfig: Workspace.SearchConfig.SearchConfig|null;
249
+ #pendingSearchConfig: Workspace.SearchConfig.SearchConfig|null;
250
+ #searchResultsPane: SearchResultsPane|null;
251
+ #progressIndicator: UI.ProgressIndicator.ProgressIndicator|null;
252
+ #visiblePane: UI.Widget.Widget|null;
253
+ #searchResultsElement!: HTMLElement;
254
+ #query: string;
255
+ #matchCase = false;
256
+ #isRegex = false;
257
+ #searchMessage = '';
258
+ #searchProgressPlaceholderElement!: HTMLElement;
259
+ #searchResultsMessage = '';
260
+ readonly #advancedSearchConfig: Common.Settings.Setting<{
261
+ query: string,
262
+ ignoreCase: boolean,
263
+ isRegex: boolean,
264
+ }>;
265
+ #searchScope: SearchScope|null;
266
+
267
+ // We throttle adding search results, otherwise we trigger DOM layout for each
268
+ // result added.
269
+ #throttler: Common.Throttler.Throttler;
270
+ #pendingSearchResults: SearchResult[] = [];
271
+ #emptyStartView: UI.EmptyWidget.EmptyWidget;
272
+
273
+ constructor(settingKey: string, throttler: Common.Throttler.Throttler, view = DEFAULT_VIEW) {
274
+ super({
275
+ jslog: `${VisualLogging.panel('search').track({resize: true})}`,
276
+ useShadowDom: true,
277
+ });
278
+ this.#view = view;
279
+ this.setMinimumSize(0, 40);
280
+
281
+ this.#focusSearchInput = false;
282
+ this.#isIndexing = false;
283
+ this.#searchId = 1;
284
+ this.#query = '';
285
+ this.#searchMatchesCount = 0;
286
+ this.#searchResultsCount = 0;
287
+ this.#nonEmptySearchResultsCount = 0;
288
+ this.#searchingView = null;
289
+ this.#notFoundView = null;
290
+ this.#searchConfig = null;
291
+ this.#pendingSearchConfig = null;
292
+ this.#searchResultsPane = null;
293
+ this.#progressIndicator = null;
294
+ this.#visiblePane = null;
295
+ this.#throttler = throttler;
246
296
 
247
297
  this.#advancedSearchConfig = Common.Settings.Settings.instance().createLocalSetting(
248
298
  settingKey + '-search-config', new Workspace.SearchConfig.SearchConfig('', true, false).toPlainObject());
249
299
 
300
+ this.performUpdate();
250
301
  this.#load();
302
+ this.performUpdate();
251
303
  this.#searchScope = null;
252
304
 
253
305
  this.#emptyStartView = new UI.EmptyWidget.EmptyWidget(
@@ -257,28 +309,54 @@ export class SearchView extends UI.Widget.VBox {
257
309
  this.#showPane(this.#emptyStartView);
258
310
  }
259
311
 
312
+ override performUpdate(): void {
313
+ const input: SearchViewInput = {
314
+ query: this.#query,
315
+ focusSearchInput: this.#focusSearchInput,
316
+ matchCase: this.#matchCase,
317
+ isRegex: this.#isRegex,
318
+ searchMessage: this.#searchMessage,
319
+ searchResultsMessage: this.#searchResultsMessage,
320
+ onQueryChange: (query: string) => {
321
+ this.#query = query;
322
+ },
323
+ onQueryKeyDown: this.#onQueryKeyDown.bind(this),
324
+ onPanelKeyDown: this.#onPanelKeyDown.bind(this),
325
+ onClearSearchInput: this.#onClearSearchInput.bind(this),
326
+ onToggleRegex: this.#onToggleRegex.bind(this),
327
+ onToggleMatchCase: this.#onToggleMatchCase.bind(this),
328
+ onRefresh: this.#onRefresh.bind(this),
329
+ onClearSearch: this.#onClearSearch.bind(this),
330
+ };
331
+ const output: SearchViewOutput = {};
332
+ this.#view(input, output, this.contentElement);
333
+ this.#focusSearchInput = false;
334
+ if (output.searchResultsElement) {
335
+ this.#searchResultsElement = output.searchResultsElement;
336
+ }
337
+ if (output.searchProgressPlaceholderElement) {
338
+ this.#searchProgressPlaceholderElement = output.searchProgressPlaceholderElement;
339
+ }
340
+ }
341
+
260
342
  #onToggleRegex(): void {
261
- this.#regexButton.title = this.#regexButton.toggled ? i18nString(UIStrings.disableRegularExpression) :
262
- i18nString(UIStrings.enableRegularExpression);
343
+ this.#isRegex = !this.#isRegex;
344
+ this.performUpdate();
263
345
  }
264
346
 
265
347
  #onToggleMatchCase(): void {
266
- this.#matchCaseButton.title = this.#matchCaseButton.toggled ? i18nString(UIStrings.disableCaseSensitive) :
267
- i18nString(UIStrings.enableCaseSensitive);
348
+ this.#matchCase = !this.#matchCase;
349
+ this.performUpdate();
268
350
  }
269
351
 
270
352
  #buildSearchConfig(): Workspace.SearchConfig.SearchConfig {
271
- return new Workspace.SearchConfig.SearchConfig(
272
- this.#searchInputElement.value, !this.#matchCaseButton.toggled, this.#regexButton.toggled);
353
+ return new Workspace.SearchConfig.SearchConfig(this.#query, !this.#matchCase, this.#isRegex);
273
354
  }
274
355
 
275
356
  toggle(queryCandidate: string, searchImmediately?: boolean): void {
276
- this.#searchInputElement.value = queryCandidate;
277
- if (this.isShowing()) {
278
- this.focus();
279
- } else {
280
- this.#focusOnShow = true;
281
- }
357
+ this.#query = queryCandidate;
358
+ this.requestUpdate();
359
+ this.focus();
282
360
 
283
361
  this.#initScope();
284
362
  if (searchImmediately) {
@@ -296,14 +374,6 @@ export class SearchView extends UI.Widget.VBox {
296
374
  this.#searchScope = this.createScope();
297
375
  }
298
376
 
299
- override wasShown(): void {
300
- super.wasShown();
301
- if (this.#focusOnShow) {
302
- this.focus();
303
- this.#focusOnShow = false;
304
- }
305
- }
306
-
307
377
  #onIndexingFinished(): void {
308
378
  if (!this.#progressIndicator) {
309
379
  return;
@@ -313,10 +383,11 @@ export class SearchView extends UI.Widget.VBox {
313
383
  this.#progressIndicator.done();
314
384
  this.#progressIndicator = null;
315
385
  this.#isIndexing = false;
316
- this.#searchMessageElement.textContent = finished ? '' : i18nString(UIStrings.indexingInterrupted);
386
+ this.#searchMessage = finished ? '' : i18nString(UIStrings.indexingInterrupted);
317
387
  if (!finished) {
318
388
  this.#pendingSearchConfig = null;
319
389
  }
390
+ this.performUpdate();
320
391
  if (!this.#pendingSearchConfig) {
321
392
  return;
322
393
  }
@@ -331,8 +402,9 @@ export class SearchView extends UI.Widget.VBox {
331
402
  this.#progressIndicator.done();
332
403
  }
333
404
  this.#progressIndicator = document.createElement('devtools-progress');
334
- this.#searchMessageElement.textContent = i18nString(UIStrings.indexing);
405
+ this.#searchMessage = i18nString(UIStrings.indexing);
335
406
  this.#searchProgressPlaceholderElement.appendChild(this.#progressIndicator);
407
+ this.performUpdate();
336
408
  if (this.#searchScope) {
337
409
  this.#searchScope.performIndexing(
338
410
  new Common.Progress.ProgressProxy(this.#progressIndicator, this.#onIndexingFinished.bind(this)));
@@ -340,7 +412,8 @@ export class SearchView extends UI.Widget.VBox {
340
412
  }
341
413
 
342
414
  #onClearSearchInput(): void {
343
- this.#searchInputElement.value = '';
415
+ this.#query = '';
416
+ this.requestUpdate();
344
417
  this.#save();
345
418
  this.focus();
346
419
  this.#showPane(this.#emptyStartView);
@@ -385,8 +458,7 @@ export class SearchView extends UI.Widget.VBox {
385
458
  }
386
459
  this.#searchFinished(finished);
387
460
  this.#searchConfig = null;
388
- UI.ARIAUtils.LiveAnnouncer.alert(
389
- this.#searchMessageElement.textContent + ' ' + this.#searchResultsMessageElement.textContent);
461
+ UI.ARIAUtils.LiveAnnouncer.alert(this.#searchMessage + ' ' + this.#searchResultsMessage);
390
462
  }
391
463
 
392
464
  #innerStartSearch(searchConfig: Workspace.SearchConfig.SearchConfig): void {
@@ -407,8 +479,9 @@ export class SearchView extends UI.Widget.VBox {
407
479
  this.#stopSearch();
408
480
  this.#showPane(null);
409
481
  this.#searchResultsPane = null;
410
- this.#searchMessageElement.textContent = '';
411
- this.#searchResultsMessageElement.textContent = '';
482
+ this.#searchMessage = '';
483
+ this.#searchResultsMessage = '';
484
+ this.performUpdate();
412
485
  }
413
486
 
414
487
  #stopSearch(): void {
@@ -429,7 +502,8 @@ export class SearchView extends UI.Widget.VBox {
429
502
  this.#searchingView = new UI.EmptyWidget.EmptyWidget(i18nString(UIStrings.searching), '');
430
503
  }
431
504
  this.#showPane(this.#searchingView);
432
- this.#searchMessageElement.textContent = i18nString(UIStrings.searching);
505
+ this.#searchMessage = i18nString(UIStrings.searching);
506
+ this.performUpdate();
433
507
  this.#searchProgressPlaceholderElement.appendChild(progressIndicator);
434
508
  this.#updateSearchResultsMessage();
435
509
  }
@@ -437,18 +511,18 @@ export class SearchView extends UI.Widget.VBox {
437
511
  #updateSearchResultsMessage(): void {
438
512
  if (this.#searchMatchesCount && this.#searchResultsCount) {
439
513
  if (this.#searchMatchesCount === 1 && this.#nonEmptySearchResultsCount === 1) {
440
- this.#searchResultsMessageElement.textContent = i18nString(UIStrings.foundMatchingLineInFile);
514
+ this.#searchResultsMessage = i18nString(UIStrings.foundMatchingLineInFile);
441
515
  } else if (this.#searchMatchesCount > 1 && this.#nonEmptySearchResultsCount === 1) {
442
- this.#searchResultsMessageElement.textContent =
443
- i18nString(UIStrings.foundDMatchingLinesInFile, {PH1: this.#searchMatchesCount});
516
+ this.#searchResultsMessage = i18nString(UIStrings.foundDMatchingLinesInFile, {PH1: this.#searchMatchesCount});
444
517
  } else {
445
- this.#searchResultsMessageElement.textContent = i18nString(
518
+ this.#searchResultsMessage = i18nString(
446
519
  UIStrings.foundDMatchingLinesInDFiles,
447
520
  {PH1: this.#searchMatchesCount, PH2: this.#nonEmptySearchResultsCount});
448
521
  }
449
522
  } else {
450
- this.#searchResultsMessageElement.textContent = '';
523
+ this.#searchResultsMessage = '';
451
524
  }
525
+ this.performUpdate();
452
526
  }
453
527
 
454
528
  #showPane(panel: UI.Widget.Widget|null): void {
@@ -480,13 +554,13 @@ export class SearchView extends UI.Widget.VBox {
480
554
  }
481
555
 
482
556
  #searchFinished(finished: boolean): void {
483
- this.#searchMessageElement.textContent =
484
- finished ? i18nString(UIStrings.searchFinished) : i18nString(UIStrings.searchInterrupted);
557
+ this.#searchMessage = finished ? i18nString(UIStrings.searchFinished) : i18nString(UIStrings.searchInterrupted);
558
+ this.performUpdate();
485
559
  }
486
560
 
487
561
  override focus(): void {
488
- this.#searchInputElement.focus();
489
- this.#searchInputElement.select();
562
+ this.#focusSearchInput = true;
563
+ this.requestUpdate();
490
564
  }
491
565
 
492
566
  override willHide(): void {
@@ -550,13 +624,11 @@ export class SearchView extends UI.Widget.VBox {
550
624
 
551
625
  #load(): void {
552
626
  const searchConfig = Workspace.SearchConfig.SearchConfig.fromPlainObject(this.#advancedSearchConfig.get());
553
- this.#searchInputElement.value = searchConfig.query();
627
+ this.#query = searchConfig.query();
554
628
 
555
- this.#matchCaseButton.toggled = !searchConfig.ignoreCase();
556
- this.#onToggleMatchCase();
557
-
558
- this.#regexButton.toggled = searchConfig.isRegex();
559
- this.#onToggleRegex();
629
+ this.#matchCase = !searchConfig.ignoreCase();
630
+ this.#isRegex = searchConfig.isRegex();
631
+ this.requestUpdate();
560
632
  }
561
633
 
562
634
  #onRefresh(): void {
@@ -581,16 +653,4 @@ export class SearchView extends UI.Widget.VBox {
581
653
  get throttlerForTest(): Common.Throttler.Throttler {
582
654
  return this.#throttler;
583
655
  }
584
-
585
- get search(): HTMLInputElement {
586
- return this.#searchInputElement;
587
- }
588
-
589
- get matchCaseButton(): Buttons.Button.Button {
590
- return this.#matchCaseButton;
591
- }
592
-
593
- get regexButton(): Buttons.Button.Button {
594
- return this.#regexButton;
595
- }
596
656
  }
@@ -77,20 +77,56 @@ const UIStrings = {
77
77
  * @description Label for Sign-Up button for the Google Developer Program profiles.
78
78
  */
79
79
  signUp: 'Sign up',
80
+ /**
81
+ * @description Link text for opening the Google Developer Program profile page.
82
+ */
83
+ viewProfile: 'View profile',
84
+ /**
85
+ * @description Text for tooltip shown on hovering over "Relevant Data" in the disclaimer text for AI code completion.
86
+ */
87
+ tooltipDisclaimerText:
88
+ 'When you qualify for a badge, the badge’s identifier and the type of activity you did to earn it are sent to Google',
80
89
  /**
81
90
  * @description Text for the data notice right after the settings checkbox.
82
91
  */
83
- relevantDataDisclaimer: '(Relevant data is sent to Google)',
92
+ relevantData: 'Relevant data',
84
93
  /**
85
- * @description Link text for opening the Google Developer Program profile page.
94
+ * @description Text for the data notice right after the settings checkbox.
95
+ * @example {Relevant data} PH1
86
96
  */
87
- viewProfile: 'View profile',
97
+ dataDisclaimer: '({PH1} is sent to Google)',
88
98
  } as const;
89
99
  const str_ = i18n.i18n.registerUIStrings('panels/settings/components/SyncSection.ts', UIStrings);
90
100
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
91
101
 
92
102
  const {html, Directives: {ref, createRef}} = Lit;
93
103
 
104
+ let cachedTooltipElement: HTMLElement|undefined;
105
+
106
+ function renderDataDisclaimer(): HTMLElement {
107
+ if (cachedTooltipElement) {
108
+ return cachedTooltipElement;
109
+ }
110
+
111
+ const relevantDataTooltipTemplate = html`
112
+ <span
113
+ tabIndex="0"
114
+ class="link"
115
+ aria-details="gdp-profile-tooltip"
116
+ aria-describedby="gdp-profile-tooltip"
117
+ >${i18nString(UIStrings.relevantData)}</span>
118
+ <devtools-tooltip id="gdp-profile-tooltip" variant=${'rich'}>
119
+ <div class="tooltip-content" tabindex="0">${i18nString(UIStrings.tooltipDisclaimerText)}</div>
120
+ </devtools-tooltip>`;
121
+
122
+ const container = document.createElement('span');
123
+ Lit.render(relevantDataTooltipTemplate, container);
124
+ cachedTooltipElement = i18n.i18n.getFormatLocalizedString(str_, UIStrings.dataDisclaimer, {
125
+ PH1: container,
126
+ });
127
+ return cachedTooltipElement;
128
+ }
129
+
94
130
  function getGdpSubscriptionText(profile: Host.GdpClient.Profile): Platform.UIString.LocalizedString {
95
131
  if (!profile.activeSubscription ||
96
132
  profile.activeSubscription.subscriptionStatus !== Host.GdpClient.SubscriptionStatus.ENABLED) {
@@ -124,14 +160,19 @@ export class SyncSection extends HTMLElement {
124
160
  #syncSetting?: Common.Settings.Setting<boolean>;
125
161
  #receiveBadgesSetting?: Common.Settings.Setting<boolean>;
126
162
  #receiveBadgesSettingContainerRef = createRef<HTMLElement>();
163
+ #isEligibleToCreateGdpProfile = false;
127
164
  #gdpProfile?: Host.GdpClient.Profile;
128
165
 
129
166
  set data(data: SyncSectionData) {
130
167
  this.#syncInfo = data.syncInfo;
131
168
  this.#syncSetting = data.syncSetting;
132
169
  this.#receiveBadgesSetting = data.receiveBadgesSetting;
133
- void this.#updateGdpProfile();
134
170
  void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
171
+
172
+ // Trigger fetching GDP profile if the user is signed in.
173
+ if (data.syncInfo.accountEmail) {
174
+ void this.#fetchGdpDetails();
175
+ }
135
176
  }
136
177
 
137
178
  async highlightReceiveBadgesSetting(): Promise<void> {
@@ -161,15 +202,21 @@ export class SyncSection extends HTMLElement {
161
202
  ${renderGdpSectionIfNeeded({
162
203
  receiveBadgesSetting: this.#receiveBadgesSetting,
163
204
  receiveBadgesSettingContainerRef: this.#receiveBadgesSettingContainerRef,
164
- gdpProfile: this.#gdpProfile
205
+ gdpProfile: this.#gdpProfile,
206
+ isEligibleToCreateProfile: this.#isEligibleToCreateGdpProfile,
165
207
  })}
166
208
  </fieldset>
167
209
  `, this.#shadow, {host: this});
168
210
  // clang-format on
169
211
  }
170
212
 
171
- async #updateGdpProfile(): Promise<void> {
213
+ async #fetchGdpDetails(): Promise<void> {
214
+ if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled) {
215
+ return;
216
+ }
217
+
172
218
  this.#gdpProfile = await Host.GdpClient.GdpClient.instance().getProfile() ?? undefined;
219
+ this.#isEligibleToCreateGdpProfile = await Host.GdpClient.GdpClient.instance().isEligibleToCreateProfile();
173
220
  void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
174
221
  }
175
222
  }
@@ -247,20 +294,22 @@ function renderGdpSectionIfNeeded({
247
294
  receiveBadgesSetting,
248
295
  receiveBadgesSettingContainerRef,
249
296
  gdpProfile,
297
+ isEligibleToCreateProfile,
250
298
  }: {
251
299
  receiveBadgesSettingContainerRef: Lit.Directives.Ref<HTMLElement>,
252
300
  receiveBadgesSetting?: Common.Settings.Setting<boolean>,
253
301
  gdpProfile?: Host.GdpClient.Profile,
302
+ isEligibleToCreateProfile?: boolean,
254
303
  }): Lit.LitTemplate {
255
304
  // clang-format off
256
- if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled) {
305
+ if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled || (!gdpProfile && !isEligibleToCreateProfile)) {
257
306
  return Lit.nothing;
258
307
  }
259
308
 
260
309
  function renderBrand(): Lit.LitTemplate {
261
310
  return html`
262
311
  <div class="gdp-profile-header">
263
- <div class="gdp-logo" role="img" aria-label="Google Developer Program"></div>
312
+ <div class="gdp-logo" role="img" tabindex="0" aria-label="Google Developer Program"></div>
264
313
  </div>
265
314
  `;
266
315
  }
@@ -289,7 +338,7 @@ function renderGdpSectionIfNeeded({
289
338
  Badges.UserBadges.instance().recordAction(Badges.BadgeAction.RECEIVE_BADGES_SETTING_ENABLED);
290
339
  });
291
340
  }}></setting-checkbox>
292
- <span>${i18nString(UIStrings.relevantDataDisclaimer)}</span>
341
+ ${renderDataDisclaimer()}
293
342
  </div>` : Lit.nothing}
294
343
  </div>
295
344
  ` : html`
@@ -114,5 +114,11 @@ fieldset {
114
114
  align-items: center;
115
115
  gap: var(--sys-size-2);
116
116
  }
117
+
118
+ & .tooltip-content {
119
+ max-width: 278px;
120
+ padding: var(--sys-size-2) var(--sys-size-3);
121
+ font: var(--sys-typescale-body5-regular);
122
+ }
117
123
  }
118
124
  }
@@ -87,10 +87,7 @@ export class AiCodeCompletionPlugin extends Plugin {
87
87
  override editorExtension(): CodeMirror.Extension {
88
88
  return [
89
89
  CodeMirror.EditorView.updateListener.of(update => this.#editorUpdate(update)), this.#teaserCompartment.of([]),
90
- // conservativeCompletion is required so that the completion suggestions in the traditional
91
- // autocomplete menu are only activated after the first keyDown/keyUp events.
92
- TextEditor.Config.conservativeCompletion, TextEditor.Config.aiAutoCompleteSuggestion,
93
- CodeMirror.Prec.highest(CodeMirror.keymap.of(this.#editorKeymap()))
90
+ TextEditor.Config.aiAutoCompleteSuggestion, CodeMirror.Prec.highest(CodeMirror.keymap.of(this.#editorKeymap()))
94
91
  ];
95
92
  }
96
93
 
@@ -748,7 +748,7 @@ export class WebauthnPaneImpl extends UI.Panel.Panel implements
748
748
  }
749
749
 
750
750
  async #handleAddAuthenticatorButton(): Promise<void> {
751
- const options = this.#newAuthenticatorOptions;
751
+ const options = {...this.#newAuthenticatorOptions};
752
752
  if (this.#model) {
753
753
  const authenticatorId = await this.#addAuthenticator(options);
754
754
  this.#activeAuthId = authenticatorId; // Newly added authenticator is automatically set as active.
@@ -1,7 +1,7 @@
1
1
  Name: Dependencies sourced from the upstream `chromium` repository
2
2
  URL: https://source.chromium.org/chromium/chromium/src/+/main:components/variations/proto/devtools/
3
3
  Version: N/A
4
- Revision: a0857bc5fc46c520d7fe71beb1b0a0d7b0e60136
4
+ Revision: a53252f55270b0a53536cabc8402ef6457ee9ab9
5
5
  Update Mechanism: Manual (https://crbug.com/428069060)
6
6
  License: BSD-3-Clause
7
7
  License File: LICENSE