chrome-devtools-frontend 1.0.1521746 → 1.0.1522145

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 (47) hide show
  1. package/front_end/core/host/GdpClient.ts +116 -66
  2. package/front_end/core/root/Runtime.ts +1 -0
  3. package/front_end/entrypoints/inspector_main/InspectorMain.ts +82 -32
  4. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -1
  5. package/front_end/entrypoints/main/MainImpl.ts +7 -1
  6. package/front_end/generated/InspectorBackendCommands.js +3 -2
  7. package/front_end/generated/protocol-mapping.d.ts +9 -0
  8. package/front_end/generated/protocol-proxy-api.d.ts +8 -0
  9. package/front_end/generated/protocol.ts +12 -0
  10. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +10 -6
  11. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +42 -4
  12. package/front_end/models/badges/UserBadges.ts +14 -16
  13. package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -2
  14. package/front_end/panels/application/IndexedDBViews.ts +1 -0
  15. package/front_end/panels/application/ReportingApiTreeElement.ts +1 -2
  16. package/front_end/panels/application/ReportingApiView.ts +18 -20
  17. package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -0
  18. package/front_end/panels/application/components/EndpointsGrid.ts +51 -59
  19. package/front_end/panels/application/components/ReportsGrid.ts +86 -107
  20. package/front_end/panels/application/components/StorageMetadataView.ts +30 -4
  21. package/front_end/panels/application/components/endpointsGrid.css +30 -0
  22. package/front_end/panels/application/components/reportsGrid.css +34 -0
  23. package/front_end/panels/application/components/storageMetadataView.css +9 -0
  24. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +19 -27
  25. package/front_end/panels/common/BadgeNotification.ts +10 -3
  26. package/front_end/panels/network/NetworkPanel.ts +1 -1
  27. package/front_end/panels/search/SearchResultsPane.ts +14 -13
  28. package/front_end/panels/search/SearchView.ts +3 -20
  29. package/front_end/panels/settings/components/SyncSection.ts +8 -6
  30. package/front_end/panels/sources/SearchSourcesView.ts +1 -1
  31. package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -11
  32. package/front_end/panels/whats_new/resources/WNDT.md +9 -6
  33. package/front_end/third_party/chromium/README.chromium +1 -1
  34. package/front_end/third_party/diff/README.chromium +0 -1
  35. package/front_end/ui/legacy/Treeoutline.ts +6 -9
  36. package/front_end/ui/legacy/UIUtils.ts +4 -17
  37. package/front_end/ui/legacy/Widget.ts +0 -5
  38. package/front_end/ui/legacy/XElement.ts +0 -33
  39. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  40. package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +38 -21
  41. package/front_end/ui/legacy/components/perf_ui/filmStripView.css +29 -0
  42. package/front_end/ui/legacy/components/source_frame/XMLView.ts +3 -2
  43. package/front_end/ui/legacy/legacy.ts +0 -2
  44. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  45. package/package.json +1 -1
  46. package/front_end/panels/application/components/reportingApiGrid.css +0 -31
  47. package/front_end/ui/legacy/XWidget.ts +0 -133
@@ -1,23 +1,17 @@
1
1
  // Copyright 2021 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- /* eslint-disable rulesdir/no-lit-render-outside-of-view */
5
4
 
6
5
  import '../../../ui/legacy/components/data_grid/data_grid.js';
7
- import '../../../ui/components/icon_button/icon_button.js';
8
- import '../../../ui/legacy/legacy.js';
9
6
 
10
7
  import * as i18n from '../../../core/i18n/i18n.js';
11
8
  import * as Root from '../../../core/root/root.js';
12
9
  import type * as Protocol from '../../../generated/protocol.js';
13
- // inspectorCommonStyles is imported for the empty state styling that is used for the start view
14
- // eslint-disable-next-line rulesdir/es-modules-import
15
- import inspectorCommonStyles from '../../../ui/legacy/inspectorCommon.css.js';
16
10
  import * as UI from '../../../ui/legacy/legacy.js';
17
11
  import * as Lit from '../../../ui/lit/lit.js';
18
12
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
19
13
 
20
- import reportingApiGridStyles from './reportingApiGrid.css.js';
14
+ import reportsGridStyles from './reportsGrid.css.js';
21
15
 
22
16
  const UIStrings = {
23
17
  /**
@@ -48,7 +42,7 @@ const UIStrings = {
48
42
  * @description Column header for a table displaying Reporting API reports.
49
43
  *The column contains the timestamp of when a report was generated.
50
44
  */
51
- generatedAt: 'Generated at'
45
+ generatedAt: 'Generated at',
52
46
  } as const;
53
47
  const str_ = i18n.i18n.registerUIStrings('panels/application/components/ReportsGrid.ts', UIStrings);
54
48
  export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -57,115 +51,100 @@ const {render, html} = Lit;
57
51
 
58
52
  const REPORTING_API_EXPLANATION_URL = 'https://developer.chrome.com/docs/capabilities/web-apis/reporting-api';
59
53
 
60
- export class ReportsGridStatusHeader extends HTMLElement {
61
- readonly #shadow = this.attachShadow({mode: 'open'});
62
-
63
- connectedCallback(): void {
64
- this.#render();
65
- }
66
-
67
- #render(): void {
68
- // Disabled until https://crbug.com/1079231 is fixed.
69
- // clang-format off
70
- render(html`
71
- <style>${reportingApiGridStyles}</style>
72
- <span class="status-header">${i18nString(UIStrings.status)}</span>
73
- <x-link href="https://web.dev/reporting-api/#report-status"
74
- jslog=${VisualLogging.link('report-status').track({click: true})}>
75
- <devtools-icon class="inline-icon medium" name="help" style="color: var(--icon-link);"></devtools-icon>
76
- </x-link>
77
- `, this.#shadow, {host: this});
78
- // clang-format on
79
- }
80
- }
81
-
82
54
  export interface ReportsGridData {
83
55
  reports: Protocol.Network.ReportingApiReport[];
84
56
  }
85
57
 
86
- export class ReportsGrid extends HTMLElement {
87
- readonly #shadow = this.attachShadow({mode: 'open'});
88
- #reports: Protocol.Network.ReportingApiReport[] = [];
89
- #protocolMonitorExperimentEnabled = false;
58
+ export interface ViewInput {
59
+ reports: Protocol.Network.ReportingApiReport[];
60
+ protocolMonitorExperimentEnabled: boolean;
61
+ onSelect: (e: CustomEvent<HTMLElement|null>) => void;
62
+ }
90
63
 
91
- connectedCallback(): void {
92
- this.#protocolMonitorExperimentEnabled = Root.Runtime.experiments.isEnabled('protocol-monitor');
93
- this.#render();
94
- }
64
+ export const DEFAULT_VIEW = (input: ViewInput, output: undefined, target: HTMLElement): void => {
65
+ // clang-format off
66
+ render(html`
67
+ <style>${reportsGridStyles}</style>
68
+ <style>${UI.inspectorCommonStyles}</style>
69
+ <div class="reporting-container" jslog=${VisualLogging.section('reports')}>
70
+ <div class="reporting-header">${i18n.i18n.lockedString('Reports')}</div>
71
+ ${input.reports.length > 0 ? html`
72
+ <devtools-data-grid striped @select=${input.onSelect}>
73
+ <table>
74
+ <tr>
75
+ ${input.protocolMonitorExperimentEnabled ? html`
76
+ <th id="id" weight="30">${i18n.i18n.lockedString('ID')}</th>
77
+ ` : ''}
78
+ <th id="url" weight="30">${i18n.i18n.lockedString('URL')}</th>
79
+ <th id="type" weight="20">${i18n.i18n.lockedString('Type')}</th>
80
+ <th id="status" weight="20">
81
+ <style>${reportsGridStyles}</style>
82
+ <span class="status-header">${i18nString(UIStrings.status)}</span>
83
+ <x-link href="https://web.dev/reporting-api/#report-status"
84
+ jslog=${VisualLogging.link('report-status').track({click: true})}>
85
+ <devtools-icon class="inline-icon medium" name="help" style="color: var(--icon-link);"
86
+ ></devtools-icon>
87
+ </x-link>
88
+ </th>
89
+ <th id="destination" weight="20">${i18nString(UIStrings.destination)}</th>
90
+ <th id="timestamp" weight="20">${i18nString(UIStrings.generatedAt)}</th>
91
+ <th id="body" weight="20">${i18n.i18n.lockedString('Body')}</th>
92
+ </tr>
93
+ ${input.reports.map(report => html`
94
+ <tr data-id=${report.id}>
95
+ ${input.protocolMonitorExperimentEnabled ? html`<td>${report.id}</td>` : ''}
96
+ <td>${report.initiatorUrl}</td>
97
+ <td>${report.type}</td>
98
+ <td>${report.status}</td>
99
+ <td>${report.destination}</td>
100
+ <td>${new Date(report.timestamp * 1000).toLocaleString()}</td>
101
+ <td>${JSON.stringify(report.body)}</td>
102
+ </tr>
103
+ `)}
104
+ </table>
105
+ </devtools-data-grid>
106
+ ` : html`
107
+ <div class="empty-state">
108
+ <span class="empty-state-header">${i18nString(UIStrings.noReportsToDisplay)}</span>
109
+ <div class="empty-state-description">
110
+ <span>${i18nString(UIStrings.reportingApiDescription)}</span>
111
+ ${UI.XLink.XLink.create(REPORTING_API_EXPLANATION_URL, i18nString(UIStrings.learnMore), undefined,
112
+ undefined, 'learn-more')}
113
+ </div>
114
+ </div>
115
+ `}
116
+ </div>
117
+ `, target);
118
+ // clang-format on
119
+ };
95
120
 
96
- set data(data: ReportsGridData) {
97
- this.#reports = data.reports;
98
- this.#render();
99
- }
121
+ type View = typeof DEFAULT_VIEW;
100
122
 
101
- get data(): ReportsGridData {
102
- return {reports: this.#reports};
103
- }
123
+ export class ReportsGrid extends UI.Widget.Widget {
124
+ reports: Protocol.Network.ReportingApiReport[] = [];
125
+ #protocolMonitorExperimentEnabled = false;
126
+ #view: View;
127
+ onReportSelected: (id: string) => void = () => {};
104
128
 
105
- #render(): void {
106
- // Disabled until https://crbug.com/1079231 is fixed.
107
- // clang-format off
108
- render(html`
109
- <style>${reportingApiGridStyles}</style>
110
- <style>${inspectorCommonStyles}</style>
111
- <div class="reporting-container" jslog=${VisualLogging.section('reports')}>
112
- <div class="reporting-header">${i18n.i18n.lockedString('Reports')}</div>
113
- ${this.#reports.length > 0 ? html`
114
- <devtools-data-grid striped @select=${this.#onSelect}>
115
- <table>
116
- <tr>
117
- ${this.#protocolMonitorExperimentEnabled ? html`
118
- <th id="id" weight="30">${i18n.i18n.lockedString('ID')}</th>
119
- ` : ''}
120
- <th id="url" weight="30">${i18n.i18n.lockedString('URL')}</th>
121
- <th id="type" weight="20">${i18n.i18n.lockedString('Type')}</th>
122
- <th id="status" weight="20">
123
- <devtools-resources-reports-grid-status-header></devtools-resources-reports-grid-status-header>
124
- </th>
125
- <th id="destination" weight="20">${i18nString(UIStrings.destination)}</th>
126
- <th id="timestamp" weight="20">${i18nString(UIStrings.generatedAt)}</th>
127
- <th id="body" weight="20">${i18n.i18n.lockedString('Body')}</th>
128
- </tr>
129
- ${this.#reports.map(report => html`
130
- <tr data-id=${report.id}>
131
- ${this.#protocolMonitorExperimentEnabled ? html`<td>${report.id}</td>` : ''}
132
- <td>${report.initiatorUrl}</td>
133
- <td>${report.type}</td>
134
- <td>${report.status}</td>
135
- <td>${report.destination}</td>
136
- <td>${new Date(report.timestamp * 1000).toLocaleString()}</td>
137
- <td>${JSON.stringify(report.body)}</td>
138
- </tr>
139
- `)}
140
- </table>
141
- </devtools-data-grid>
142
- ` : html`
143
- <div class="empty-state">
144
- <span class="empty-state-header">${i18nString(UIStrings.noReportsToDisplay)}</span>
145
- <div class="empty-state-description">
146
- <span>${i18nString(UIStrings.reportingApiDescription)}</span>
147
- ${UI.XLink.XLink.create(REPORTING_API_EXPLANATION_URL, i18nString(UIStrings.learnMore), undefined, undefined, 'learn-more')}
148
- </div>
149
- </div>
150
- `}
151
- </div>
152
- `, this.#shadow, {host: this});
153
- // clang-format on
129
+ constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
130
+ super(element);
131
+ this.#view = view;
132
+ this.#protocolMonitorExperimentEnabled = Root.Runtime.experiments.isEnabled('protocol-monitor');
133
+ this.requestUpdate();
154
134
  }
155
135
 
156
- #onSelect(e: CustomEvent<HTMLElement|null>): void {
157
- if (e.detail) {
158
- this.dispatchEvent(new CustomEvent('select', {detail: e.detail.dataset.id}));
136
+ #onSelect = (e: CustomEvent<HTMLElement|null>): void => {
137
+ if (e.detail?.dataset.id) {
138
+ this.onReportSelected(e.detail.dataset.id);
159
139
  }
160
- }
161
- }
162
-
163
- customElements.define('devtools-resources-reports-grid-status-header', ReportsGridStatusHeader);
164
- customElements.define('devtools-resources-reports-grid', ReportsGrid);
165
-
166
- declare global {
167
- interface HTMLElementTagNameMap {
168
- 'devtools-resources-reports-grid-status-header': ReportsGridStatusHeader;
169
- 'devtools-resources-reports-grid': ReportsGrid;
140
+ };
141
+
142
+ override performUpdate(): void {
143
+ const viewInput = {
144
+ reports: this.reports,
145
+ protocolMonitorExperimentEnabled: this.#protocolMonitorExperimentEnabled,
146
+ onSelect: this.#onSelect,
147
+ };
148
+ this.#view(viewInput, undefined, this.contentElement);
170
149
  }
171
150
  }
@@ -14,6 +14,8 @@ import * as RenderCoordinator from '../../../ui/components/render_coordinator/re
14
14
  import * as UI from '../../../ui/legacy/legacy.js';
15
15
  import * as Lit from '../../../ui/lit/lit.js';
16
16
 
17
+ import storageMetadataViewStyle from './storageMetadataView.css.js';
18
+
17
19
  const {html} = Lit;
18
20
 
19
21
  const UIStrings = {
@@ -21,7 +23,7 @@ const UIStrings = {
21
23
  * @description The origin of a URL (https://web.dev/same-site-same-origin/#origin).
22
24
  *(for a lot of languages this does not need to be translated, please translate only where necessary)
23
25
  */
24
- origin: 'Origin',
26
+ origin: 'Frame origin',
25
27
  /**
26
28
  * @description Site (https://web.dev/same-site-same-origin/#site) for the URL the user sees in the omnibox.
27
29
  */
@@ -118,6 +120,7 @@ export class StorageMetadataView extends LegacyWrapper.LegacyWrapper.WrappableCo
118
120
  #storageBucketsModel?: SDK.StorageBucketsModel.StorageBucketsModel;
119
121
  #storageKey: SDK.StorageKeyManager.StorageKey|null = null;
120
122
  #storageBucket: Protocol.Storage.StorageBucketInfo|null = null;
123
+ #showOnlyBucket = true;
121
124
 
122
125
  setStorageKey(storageKey: string): void {
123
126
  this.#storageKey = SDK.StorageKeyManager.parseStorageKey(storageKey);
@@ -129,6 +132,10 @@ export class StorageMetadataView extends LegacyWrapper.LegacyWrapper.WrappableCo
129
132
  this.setStorageKey(storageBucket.bucket.storageKey);
130
133
  }
131
134
 
135
+ setShowOnlyBucket(show: boolean): void {
136
+ this.#showOnlyBucket = show;
137
+ }
138
+
132
139
  enableStorageBucketControls(model: SDK.StorageBucketsModel.StorageBucketsModel): void {
133
140
  this.#storageBucketsModel = model;
134
141
  if (this.#storageKey) {
@@ -141,6 +148,9 @@ export class StorageMetadataView extends LegacyWrapper.LegacyWrapper.WrappableCo
141
148
  // Disabled until https://crbug.com/1079231 is fixed.
142
149
  // clang-format off
143
150
  Lit.render(html`
151
+ <style>
152
+ ${storageMetadataViewStyle}
153
+ </style>
144
154
  <devtools-report .data=${{reportTitle: this.getTitle() ?? i18nString(UIStrings.loading)}}>
145
155
  ${await this.renderReportContent()}
146
156
  </devtools-report>`, this.#shadow, {host: this});
@@ -181,11 +191,16 @@ export class StorageMetadataView extends LegacyWrapper.LegacyWrapper.WrappableCo
181
191
  topLevelSiteIsOpaque ? i18nString(UIStrings.yesBecauseTopLevelIsOpaque) :
182
192
  (topLevelSite && origin !== topLevelSite) ? i18nString(UIStrings.yesBecauseOriginNotInTopLevelSite) :
183
193
  null;
194
+
195
+ const isIframeOrEmbedded = topLevelSite && origin !== topLevelSite;
196
+
184
197
  // Disabled until https://crbug.com/1079231 is fixed.
185
198
  // clang-format off
186
199
  return html`
187
- ${this.key(i18nString(UIStrings.origin))}
188
- ${this.value(html`<div class="text-ellipsis" title=${origin}>${origin}</div>`)}
200
+ ${(isIframeOrEmbedded) ?
201
+ html`${this.key(i18nString(UIStrings.origin))}
202
+ ${this.value(html`<div class="text-ellipsis" title=${origin}>${origin}</div>`)}`
203
+ : Lit.nothing}
189
204
  ${(topLevelSite || topLevelSiteIsOpaque) ? this.key(i18nString(UIStrings.topLevelSite)) : Lit.nothing}
190
205
  ${topLevelSite ? this.value(topLevelSite) : Lit.nothing}
191
206
  ${topLevelSiteIsOpaque ? this.value(i18nString(UIStrings.opaque)) : Lit.nothing}
@@ -205,11 +220,22 @@ export class StorageMetadataView extends LegacyWrapper.LegacyWrapper.WrappableCo
205
220
  throw new Error('Should not call #renderStorageBucketInfo if #bucket is null.');
206
221
  }
207
222
  const {bucket: {name}, persistent, durability, quota} = this.#storageBucket;
223
+ const isDefault = !name;
208
224
 
225
+ if (!this.#showOnlyBucket) {
226
+ if (isDefault) {
227
+ return html`
228
+ ${this.key(i18nString(UIStrings.bucketName))}
229
+ ${this.value(html`<span class="default-bucket">default</span>`)}`;
230
+ }
231
+ return html`
232
+ ${this.key(i18nString(UIStrings.bucketName))}
233
+ ${this.value(name)}`;
234
+ }
209
235
  // clang-format off
210
236
  return html`
211
237
  ${this.key(i18nString(UIStrings.bucketName))}
212
- ${this.value(name || 'default')}
238
+ ${this.value(name || html`<span class="default-bucket">default</span>`)}
213
239
  ${this.key(i18nString(UIStrings.persistent))}
214
240
  ${this.value(persistent ? i18nString(UIStrings.yes) : i18nString(UIStrings.no))}
215
241
  ${this.key(i18nString(UIStrings.durability))}
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Copyright 2025 The Chromium Authors
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+ @scope to (devtools-widget > *) {
8
+ :scope {
9
+ overflow: auto;
10
+ height: 100%;
11
+ }
12
+
13
+ .endpoints-container {
14
+ height: 100%;
15
+ display: flex;
16
+ flex-direction: column;
17
+ width: 100%;
18
+ }
19
+
20
+ .endpoints-header {
21
+ font-size: 15px;
22
+ background-color: var(--sys-color-surface2);
23
+ padding: 1px 4px;
24
+ flex-shrink: 0;
25
+ }
26
+
27
+ devtools-data-grid {
28
+ flex: auto;
29
+ }
30
+ }
@@ -0,0 +1,34 @@
1
+ /*
2
+ * Copyright 2025 The Chromium Authors
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+ @scope to (devtools-widget > *) {
8
+ :scope {
9
+ overflow: auto;
10
+ height: 100%;
11
+ }
12
+
13
+ .reporting-container {
14
+ height: 100%;
15
+ display: flex;
16
+ flex-direction: column;
17
+ width: 100%;
18
+ }
19
+
20
+ .reporting-header {
21
+ font-size: 15px;
22
+ background-color: var(--sys-color-surface2);
23
+ padding: 1px 4px;
24
+ flex-shrink: 0;
25
+ }
26
+
27
+ devtools-data-grid {
28
+ flex: auto;
29
+ }
30
+
31
+ .inline-icon {
32
+ vertical-align: text-bottom;
33
+ }
34
+ }
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Copyright 2025 The Chromium Authors. All rights reserved.
3
+ * Use of this source code is governed by a BSD-style license that can be
4
+ * found in the LICENSE file.
5
+ */
6
+
7
+ .default-bucket {
8
+ font-style: italic;
9
+ }
@@ -183,29 +183,23 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
183
183
  'source-code': true,
184
184
  'breakpoint-hit': input.highlightedItem === breakpoint,
185
185
  });
186
- const categoryConfigElements = new WeakMap<HTMLLIElement, SDK.CategorizedBreakpoint.Category>();
187
- const trackCategoryConfigElement = (category: SDK.CategorizedBreakpoint.Category): ReturnType<typeof ref> =>
188
- ref((e: Element|undefined) => {
189
- if (e instanceof HTMLLIElement) {
190
- categoryConfigElements.set(e, category);
191
- }
192
- });
193
- const onExpand = ({detail: {expanded, target}}: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
194
- const category = categoryConfigElements.get(target);
195
- const breakpoints = category && input.categories.get(category);
196
- if (!breakpoints) {
197
- return;
198
- }
199
- if (shouldExpandCategory(breakpoints)) {
200
- // Basically ignore expand/collapse when the category is expanded by default.
201
- return;
202
- }
203
- if (expanded) {
204
- output.userExpandedCategories.add(category);
205
- } else {
206
- output.userExpandedCategories.delete(category);
207
- }
208
- };
186
+ const onExpand =
187
+ (category: SDK.CategorizedBreakpoint.Category, {detail: {expanded}}: UI.TreeOutline.TreeViewElement.ExpandEvent):
188
+ void => {
189
+ const breakpoints = category && input.categories.get(category);
190
+ if (!breakpoints) {
191
+ return;
192
+ }
193
+ if (shouldExpandCategory(breakpoints)) {
194
+ // Basically ignore expand/collapse when the category is expanded by default.
195
+ return;
196
+ }
197
+ if (expanded) {
198
+ output.userExpandedCategories.add(category);
199
+ } else {
200
+ output.userExpandedCategories.delete(category);
201
+ }
202
+ };
209
203
 
210
204
  render(
211
205
  // clang-format off
@@ -219,17 +213,15 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
219
213
  </devtools-toolbar>
220
214
  <devtools-tree
221
215
  ${ref(e => { output.defaultFocus = e; })}
222
- @expand=${onExpand}
223
216
  .template=${html`
224
217
  <ul role="tree">
225
218
  ${filteredCategories.map(([category, breakpoints]) => html`
226
- <li
219
+ <li @expand=${(e: UI.TreeOutline.TreeViewElement.ExpandEvent) => onExpand(category, e)}
227
220
  role="treeitem"
228
221
  jslog-context=${category}
229
222
  aria-checked=${breakpoints.some(breakpoint => breakpoint.enabled())
230
223
  ? breakpoints.some(breakpoint => !breakpoint.enabled()) ? 'mixed' : true
231
- : false}
232
- ${trackCategoryConfigElement(category)}>
224
+ : false}>
233
225
  <style>${categorizedBreakpointsSidebarPaneStyles}</style>
234
226
  <devtools-checkbox
235
227
  class="small"
@@ -192,7 +192,14 @@ export class BadgeNotification extends UI.Widget.Widget {
192
192
  }
193
193
 
194
194
  async #presentStarterBadge(badge: Badges.Badge): Promise<void> {
195
- const gdpProfile = await Host.GdpClient.GdpClient.instance().getProfile();
195
+ const getProfileResponse = await Host.GdpClient.GdpClient.instance().getProfile();
196
+ // The `getProfile` call failed and returned a `null`.
197
+ // For that case, we don't show anything.
198
+ if (!getProfileResponse) {
199
+ return;
200
+ }
201
+
202
+ const hasGdpProfile = Boolean(getProfileResponse.profile);
196
203
  const receiveBadgesSettingEnabled = Badges.UserBadges.instance().isReceiveBadgesSettingEnabled();
197
204
  const googleDeveloperProgramLink = UI.XLink.XLink.create(
198
205
  'https://developers.google.com/program', lockedString('Google Developer Program'), 'badge-link', undefined,
@@ -200,14 +207,14 @@ export class BadgeNotification extends UI.Widget.Widget {
200
207
 
201
208
  // If the user already has a GDP profile and the receive badges setting enabled,
202
209
  // starter badge behaves as if it's an activity based badge.
203
- if (gdpProfile && receiveBadgesSettingEnabled) {
210
+ if (hasGdpProfile && receiveBadgesSettingEnabled) {
204
211
  this.#presentActivityBasedBadge(badge);
205
212
  return;
206
213
  }
207
214
 
208
215
  // If the user already has a GDP profile and the receive badges setting disabled,
209
216
  // starter badge behaves as a nudge for opting into receiving badges.
210
- if (gdpProfile && !receiveBadgesSettingEnabled) {
217
+ if (hasGdpProfile && !receiveBadgesSettingEnabled) {
211
218
  this.#show({
212
219
  message: i18nFormatString(
213
220
  UIStrings.starterBadgeAwardMessageSettingDisabled, {PH1: badge.title, PH2: googleDeveloperProgramLink}),
@@ -1050,7 +1050,7 @@ let searchNetworkViewInstance: SearchNetworkView;
1050
1050
 
1051
1051
  export class SearchNetworkView extends Search.SearchView.SearchView {
1052
1052
  private constructor() {
1053
- super('network', new Common.Throttler.Throttler(/* timeoutMs */ 200));
1053
+ super('network');
1054
1054
  }
1055
1055
 
1056
1056
  static instance(opts: {
@@ -52,23 +52,24 @@ export type View = (input: ViewInput, output: unknown, target: HTMLElement) => v
52
52
  export const DEFAULT_VIEW: View = (input, _output, target) => {
53
53
  const {results, matches, expandedResults, onSelectMatch, onExpandSearchResult, onShowMoreMatches} = input;
54
54
 
55
- const onExpand = ({detail: {expanded, target}}: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
56
- const searchResultIndex = Number(target.dataset.searchResultIndex);
57
- const searchResult = results[searchResultIndex];
58
- if (expanded) {
59
- expandedResults.add(searchResult);
60
- onExpandSearchResult(searchResult);
61
- } else {
62
- expandedResults.delete(searchResult);
63
- }
64
- };
55
+ const onExpand =
56
+ (searchResult: SearchResult, {detail: {expanded}}: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
57
+ if (expanded) {
58
+ expandedResults.add(searchResult);
59
+ onExpandSearchResult(searchResult);
60
+ } else {
61
+ expandedResults.delete(searchResult);
62
+ }
63
+ };
65
64
 
66
65
  // clang-format off
67
66
  render(html`
68
- <devtools-tree hide-overflow @expand=${onExpand} .template=${html`
67
+ <devtools-tree hide-overflow .template=${html`
69
68
  <ul role="tree">
70
- ${results.map((searchResult, i) => html`
71
- <li role="treeitem" data-search-result-index=${i} class="search-result">
69
+ ${results.map(searchResult => html`
70
+ <li @expand=${(e: UI.TreeOutline.TreeViewElement.ExpandEvent) => onExpand(searchResult, e)}
71
+ role="treeitem"
72
+ class="search-result">
72
73
  <style>${searchResultsPaneStyles}</style>
73
74
  ${renderSearchResult(searchResult)}
74
75
  <ul role="group" ?hidden=${!expandedResults.has(searchResult)}>
@@ -293,12 +293,9 @@ export class SearchView extends UI.Widget.VBox {
293
293
  }>;
294
294
  #searchScope: SearchScope|null;
295
295
 
296
- // We throttle adding search results, otherwise we trigger DOM layout for each
297
- // result added.
298
- #throttler: Common.Throttler.Throttler;
299
296
  #searchResults: SearchResult[] = [];
300
297
 
301
- constructor(settingKey: string, throttler: Common.Throttler.Throttler, view = DEFAULT_VIEW) {
298
+ constructor(settingKey: string, view = DEFAULT_VIEW) {
302
299
  super({
303
300
  jslog: `${VisualLogging.panel('search').track({resize: true})}`,
304
301
  useShadowDom: true,
@@ -316,7 +313,6 @@ export class SearchView extends UI.Widget.VBox {
316
313
  this.#searchConfig = null;
317
314
  this.#pendingSearchConfig = null;
318
315
  this.#progress = null;
319
- this.#throttler = throttler;
320
316
 
321
317
  this.#advancedSearchConfig = Common.Settings.Settings.instance().createLocalSetting(
322
318
  settingKey + '-search-config', new Workspace.SearchConfig.SearchConfig('', true, false).toPlainObject());
@@ -451,17 +447,8 @@ export class SearchView extends UI.Widget.VBox {
451
447
  return;
452
448
  }
453
449
  this.#searchResults.push(searchResult);
454
- void this.#throttler.schedule(async () => this.#setSearchResults());
455
- }
456
-
457
- #setSearchResults(): void {
458
- this.#searchMatchesCount = 0;
459
- this.#searchResultsCount = 0;
460
- this.#nonEmptySearchResultsCount = 0;
461
- for (const searchResult of this.#searchResults) {
462
- this.#addSearchResult(searchResult);
463
- }
464
- this.performUpdate();
450
+ this.#addSearchResult(searchResult);
451
+ this.requestUpdate();
465
452
  }
466
453
 
467
454
  #onSearchFinished(searchId: number, finished: boolean): void {
@@ -640,8 +627,4 @@ export class SearchView extends UI.Widget.VBox {
640
627
  this.#resetSearch();
641
628
  this.#onClearSearchInput();
642
629
  }
643
-
644
- get throttlerForTest(): Common.Throttler.Throttler {
645
- return this.#throttler;
646
- }
647
630
  }
@@ -11,7 +11,6 @@ import type * as Common from '../../../core/common/common.js';
11
11
  import * as Host from '../../../core/host/host.js';
12
12
  import * as i18n from '../../../core/i18n/i18n.js';
13
13
  import type * as Platform from '../../../core/platform/platform.js';
14
- import * as Root from '../../../core/root/root.js';
15
14
  import * as SDK from '../../../core/sdk/sdk.js';
16
15
  import * as Badges from '../../../models/badges/badges.js';
17
16
  import * as Buttons from '../../../ui/components/buttons/buttons.js';
@@ -206,8 +205,13 @@ export class SyncSection extends HTMLElement {
206
205
  return;
207
206
  }
208
207
 
209
- this.#gdpProfile = await Host.GdpClient.GdpClient.instance().getProfile() ?? undefined;
210
- this.#isEligibleToCreateGdpProfile = await Host.GdpClient.GdpClient.instance().isEligibleToCreateProfile();
208
+ const getProfileResponse = await Host.GdpClient.GdpClient.instance().getProfile();
209
+ if (!getProfileResponse) {
210
+ return;
211
+ }
212
+
213
+ this.#gdpProfile = getProfileResponse.profile ?? undefined;
214
+ this.#isEligibleToCreateGdpProfile = getProfileResponse.isEligible;
211
215
  void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
212
216
  }
213
217
  }
@@ -310,9 +314,7 @@ function renderGdpSectionIfNeeded({
310
314
  if (!Host.GdpClient.isGdpProfilesAvailable() || (!gdpProfile && !isEligibleToCreateProfile)) {
311
315
  return Lit.nothing;
312
316
  }
313
- const hasReceiveBadgesCheckbox = receiveBadgesSetting &&
314
- Host.GdpClient.getGdpProfilesEnterprisePolicy() === Root.Runtime.GdpProfilesEnterprisePolicyValue.ENABLED;
315
-
317
+ const hasReceiveBadgesCheckbox = Host.GdpClient.isBadgesEnabled() && receiveBadgesSetting;
316
318
  function renderBrand(): Lit.LitTemplate {
317
319
  // clang-format off
318
320
  return html`
@@ -17,7 +17,7 @@ export class SearchSources {
17
17
 
18
18
  export class SearchSourcesView extends Search.SearchView.SearchView {
19
19
  constructor() {
20
- super('sources', new Common.Throttler.Throttler(/* timeoutMs */ 200));
20
+ super('sources');
21
21
  }
22
22
 
23
23
  override createScope(): Search.SearchScope.SearchScope {