chrome-devtools-frontend 1.0.1521880 → 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 (42) 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/models/ai_assistance/agents/NetworkAgent.ts +10 -6
  7. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +42 -4
  8. package/front_end/models/badges/UserBadges.ts +14 -16
  9. package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -2
  10. package/front_end/panels/application/IndexedDBViews.ts +1 -0
  11. package/front_end/panels/application/ReportingApiTreeElement.ts +1 -2
  12. package/front_end/panels/application/ReportingApiView.ts +18 -20
  13. package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -0
  14. package/front_end/panels/application/components/EndpointsGrid.ts +51 -59
  15. package/front_end/panels/application/components/ReportsGrid.ts +86 -107
  16. package/front_end/panels/application/components/StorageMetadataView.ts +30 -4
  17. package/front_end/panels/application/components/endpointsGrid.css +30 -0
  18. package/front_end/panels/application/components/reportsGrid.css +34 -0
  19. package/front_end/panels/application/components/storageMetadataView.css +9 -0
  20. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +19 -27
  21. package/front_end/panels/common/BadgeNotification.ts +10 -3
  22. package/front_end/panels/network/NetworkPanel.ts +1 -1
  23. package/front_end/panels/search/SearchResultsPane.ts +14 -13
  24. package/front_end/panels/search/SearchView.ts +3 -20
  25. package/front_end/panels/settings/components/SyncSection.ts +8 -6
  26. package/front_end/panels/sources/SearchSourcesView.ts +1 -1
  27. package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -11
  28. package/front_end/panels/whats_new/resources/WNDT.md +9 -6
  29. package/front_end/third_party/diff/README.chromium +0 -1
  30. package/front_end/ui/legacy/Treeoutline.ts +6 -9
  31. package/front_end/ui/legacy/UIUtils.ts +4 -17
  32. package/front_end/ui/legacy/Widget.ts +0 -5
  33. package/front_end/ui/legacy/XElement.ts +0 -33
  34. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  35. package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +38 -21
  36. package/front_end/ui/legacy/components/perf_ui/filmStripView.css +29 -0
  37. package/front_end/ui/legacy/components/source_frame/XMLView.ts +3 -2
  38. package/front_end/ui/legacy/legacy.ts +0 -2
  39. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  40. package/package.json +1 -1
  41. package/front_end/panels/application/components/reportingApiGrid.css +0 -31
  42. package/front_end/ui/legacy/XWidget.ts +0 -133
@@ -1,7 +1,6 @@
1
1
  // Copyright 2024 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- /* eslint-disable rulesdir/no-lit-render-outside-of-view */
5
4
 
6
5
  import * as Common from '../../../core/common/common.js';
7
6
  import * as Host from '../../../core/host/host.js';
@@ -273,7 +272,7 @@ export const DEFAULT_VIEW = (input: UserActionRowViewInput, output: ViewOutput,
273
272
  </div>
274
273
  </form>
275
274
  ` : Lit.nothing}
276
- `, target, {host: target});
275
+ `, target);
277
276
  // clang-format on
278
277
  };
279
278
 
@@ -146,6 +146,7 @@ export class IDBDatabaseView extends ApplicationComponents.StorageMetadataView.S
146
146
  super();
147
147
 
148
148
  this.model = model;
149
+ this.setShowOnlyBucket(false);
149
150
  if (database) {
150
151
  this.update(database);
151
152
  }
@@ -8,7 +8,6 @@ import type * as Platform from '../../core/platform/platform.js';
8
8
  import * as IconButton from '../../ui/components/icon_button/icon_button.js';
9
9
 
10
10
  import {ApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js';
11
- import * as ApplicationComponents from './components/components.js';
12
11
  import {ReportingApiView} from './ReportingApiView.js';
13
12
  import type {ResourcesPanel} from './ResourcesPanel.js';
14
13
 
@@ -37,7 +36,7 @@ export class ReportingApiTreeElement extends ApplicationPanelTreeElement {
37
36
  override onselect(selectedByUser?: boolean): boolean {
38
37
  super.onselect(selectedByUser);
39
38
  if (!this.view) {
40
- this.view = new ReportingApiView(new ApplicationComponents.EndpointsGrid.EndpointsGrid());
39
+ this.view = new ReportingApiView();
41
40
  }
42
41
  this.showView(this.view);
43
42
  Host.userMetrics.panelShown('reporting-api');
@@ -50,11 +50,10 @@ const REPORTING_API_EXPLANATION_URL =
50
50
  interface ViewInput {
51
51
  hasReports: boolean;
52
52
  hasEndpoints: boolean;
53
- // TODO (crbug.com/407940329): port EndpointsGrid to a UI Widget and instantiate it in the view
54
- endpointsGrid: ApplicationComponents.EndpointsGrid.EndpointsGrid;
55
- // TODO (crbug.com/407940381): port ReportsGrid to a UI Widget and instantiate it in the view
56
- reportsGrid: ApplicationComponents.ReportsGrid.ReportsGrid;
53
+ endpoints: Map<string, Protocol.Network.ReportingApiEndpoint[]>;
54
+ reports: Protocol.Network.ReportingApiReport[];
57
55
  focusedReport?: Protocol.Network.ReportingApiReport;
56
+ onReportSelected: (id: string) => void;
58
57
  }
59
58
 
60
59
  type View = (input: ViewInput, output: object, target: HTMLElement) => void;
@@ -68,7 +67,9 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
68
67
  ${input.hasReports ? html`
69
68
  <devtools-split-view slot="main" sidebar-position="second" sidebar-initial-size="150">
70
69
  <div slot="main">
71
- ${input.reportsGrid}
70
+ <devtools-widget .widgetConfig=${widgetConfig(ApplicationComponents.ReportsGrid.ReportsGrid, {
71
+ reports: input.reports, onReportSelected: input.onReportSelected,
72
+ })}></devtools-widget>
72
73
  </div>
73
74
  <div slot="sidebar" class="vbox" jslog=${VisualLogging.pane('preview').track({resize: true})}>
74
75
  ${input.focusedReport ? html`
@@ -85,11 +86,15 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
85
86
  </devtools-split-view>
86
87
  ` : html`
87
88
  <div slot="main">
88
- ${input.reportsGrid}
89
+ <devtools-widget .widgetConfig=${widgetConfig(ApplicationComponents.ReportsGrid.ReportsGrid, {
90
+ reports: input.reports, onReportSelected: input.onReportSelected,
91
+ })}></devtools-widget>
89
92
  </div>
90
93
  `}
91
94
  <div slot="sidebar">
92
- ${input.endpointsGrid}
95
+ <devtools-widget .widgetConfig=${widgetConfig(ApplicationComponents.EndpointsGrid.EndpointsGrid, {
96
+ endpoints: input.endpoints,
97
+ })}></devtools-widget>
93
98
  </div>
94
99
  </devtools-split-view>
95
100
  `, target);
@@ -109,20 +114,16 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
109
114
 
110
115
  export class ReportingApiView extends UI.Widget.VBox implements
111
116
  SDK.TargetManager.SDKModelObserver<SDK.NetworkManager.NetworkManager> {
112
- readonly #endpointsGrid: ApplicationComponents.EndpointsGrid.EndpointsGrid;
113
117
  #endpoints: Map<string, Protocol.Network.ReportingApiEndpoint[]>;
114
118
  #view: View;
115
119
  #networkManager?: SDK.NetworkManager.NetworkManager;
116
- #reportsGrid = new ApplicationComponents.ReportsGrid.ReportsGrid();
117
120
  #reports: Protocol.Network.ReportingApiReport[] = [];
118
121
  #focusedReport?: Protocol.Network.ReportingApiReport;
119
122
 
120
- constructor(endpointsGrid: ApplicationComponents.EndpointsGrid.EndpointsGrid, view = DEFAULT_VIEW) {
123
+ constructor(view = DEFAULT_VIEW) {
121
124
  super();
122
125
  this.#view = view;
123
- this.#endpointsGrid = endpointsGrid;
124
126
  this.#endpoints = new Map();
125
- this.#reportsGrid.addEventListener('select', this.#onFocus.bind(this));
126
127
  SDK.TargetManager.TargetManager.instance().observeModels(SDK.NetworkManager.NetworkManager, this);
127
128
  this.requestUpdate();
128
129
  }
@@ -158,35 +159,32 @@ export class ReportingApiView extends UI.Widget.VBox implements
158
159
  const viewInput = {
159
160
  hasReports: this.#reports.length > 0,
160
161
  hasEndpoints: this.#endpoints.size > 0,
161
- endpointsGrid: this.#endpointsGrid,
162
- reportsGrid: this.#reportsGrid,
162
+ endpoints: this.#endpoints,
163
+ reports: this.#reports,
163
164
  focusedReport: this.#focusedReport,
165
+ onReportSelected: this.#onReportSelected.bind(this),
164
166
  };
165
167
  this.#view(viewInput, {}, this.element);
166
168
  }
167
169
 
168
170
  #onEndpointsChangedForOrigin({data}: {data: Protocol.Network.ReportingApiEndpointsChangedForOriginEvent}): void {
169
171
  this.#endpoints.set(data.origin, data.endpoints);
170
- this.#endpointsGrid.data = {endpoints: this.#endpoints};
171
172
  this.requestUpdate();
172
173
  }
173
174
 
174
175
  #onReportAdded({data: report}: {data: Protocol.Network.ReportingApiReport}): void {
175
176
  this.#reports.push(report);
176
- this.#reportsGrid.data = {reports: this.#reports};
177
177
  this.requestUpdate();
178
178
  }
179
179
 
180
180
  #onReportUpdated({data: report}: {data: Protocol.Network.ReportingApiReport}): void {
181
181
  const index = this.#reports.findIndex(oldReport => oldReport.id === report.id);
182
182
  this.#reports[index] = report;
183
- this.#reportsGrid.data = {reports: this.#reports};
184
183
  this.requestUpdate();
185
184
  }
186
185
 
187
- async #onFocus(event: Event): Promise<void> {
188
- const selectEvent = event as CustomEvent<string>;
189
- const report = this.#reports.find(report => report.id === selectEvent.detail);
186
+ #onReportSelected(id: string): void {
187
+ const report = this.#reports.find(report => report.id === id);
190
188
  if (report) {
191
189
  this.#focusedReport = report;
192
190
  this.requestUpdate();
@@ -134,6 +134,9 @@ export class ServiceWorkerCacheView extends UI.View.SimpleView {
134
134
  const bucketInfo = this.model.target()
135
135
  .model(SDK.StorageBucketsModel.StorageBucketsModel)
136
136
  ?.getBucketByName(cache.storageBucket.storageKey, cache.storageBucket.name);
137
+
138
+ this.metadataView.setShowOnlyBucket(false);
139
+
137
140
  if (bucketInfo) {
138
141
  this.metadataView.setStorageBucket(bucketInfo);
139
142
  } else if (cache.storageKey) {
@@ -1,7 +1,6 @@
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
6
 
@@ -11,7 +10,7 @@ import * as UI from '../../../ui/legacy/legacy.js';
11
10
  import * as Lit from '../../../ui/lit/lit.js';
12
11
  import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
13
12
 
14
- import reportingApiGridStyles from './reportingApiGrid.css.js';
13
+ import endpointsGridStyles from './endpointsGrid.css.js';
15
14
 
16
15
  const UIStrings = {
17
16
  /**
@@ -23,76 +22,69 @@ const UIStrings = {
23
22
  * @description Placeholder text when there are no Reporting API endpoints.
24
23
  *(https://developers.google.com/web/updates/2018/09/reportingapi#tldr)
25
24
  */
26
- endpointsDescription: 'Here you will find the list of endpoints that receive the reports'
25
+ endpointsDescription: 'Here you will find the list of endpoints that receive the reports',
27
26
  } as const;
28
27
  const str_ = i18n.i18n.registerUIStrings('panels/application/components/EndpointsGrid.ts', UIStrings);
29
28
  export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
30
29
 
31
30
  const {render, html} = Lit;
32
31
 
33
- export interface EndpointsGridData {
32
+ export interface ViewInput {
34
33
  endpoints: Map<string, Protocol.Network.ReportingApiEndpoint[]>;
35
34
  }
36
35
 
37
- export class EndpointsGrid extends HTMLElement {
36
+ export const DEFAULT_VIEW = (input: ViewInput, output: undefined, target: HTMLElement): void => {
37
+ // clang-format off
38
+ render(html`
39
+ <style>${endpointsGridStyles}</style>
40
+ <style>${UI.inspectorCommonStyles}</style>
41
+ <div class="endpoints-container" jslog=${VisualLogging.section('endpoints')}>
42
+ <div class="endpoints-header">${i18n.i18n.lockedString('Endpoints')}</div>
43
+ ${input.endpoints.size > 0 ? html`
44
+ <devtools-data-grid striped>
45
+ <table>
46
+ <tr>
47
+ <th id="origin" weight="30">${i18n.i18n.lockedString('Origin')}</th>
48
+ <th id="name" weight="20">${i18n.i18n.lockedString('Name')}</th>
49
+ <th id="url" weight="30">${i18n.i18n.lockedString('URL')}</th>
50
+ </tr>
51
+ ${Array.from(input.endpoints).map(([origin, endpointArray]) =>
52
+ endpointArray.map(endpoint => html`<tr>
53
+ <td>${origin}</td>
54
+ <td>${endpoint.groupName}</td>
55
+ <td>${endpoint.url}</td>
56
+ </tr>`))
57
+ .flat()}
58
+ </table>
59
+ </devtools-data-grid>
60
+ ` : html`
61
+ <div class="empty-state">
62
+ <span class="empty-state-header">${i18nString(UIStrings.noEndpointsToDisplay)}</span>
63
+ <span class="empty-state-description">${i18nString(UIStrings.endpointsDescription)}</span>
64
+ </div>
65
+ `}
66
+ </div>
67
+ `, target);
68
+ // clang-format on
69
+ };
38
70
 
39
- readonly #shadow = this.attachShadow({mode: 'open'});
40
- #endpoints = new Map<string, Protocol.Network.ReportingApiEndpoint[]>();
71
+ type View = typeof DEFAULT_VIEW;
41
72
 
42
- connectedCallback(): void {
43
- this.#render();
44
- }
45
-
46
- set data(data: EndpointsGridData) {
47
- this.#endpoints = data.endpoints;
48
- this.#render();
49
- }
73
+ export class EndpointsGrid extends UI.Widget.Widget {
74
+ endpoints = new Map<string, Protocol.Network.ReportingApiEndpoint[]>();
75
+ #view: View;
50
76
 
51
- get data(): EndpointsGridData {
52
- return {endpoints: this.#endpoints};
77
+ constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
78
+ super(element);
79
+ this.#view = view;
80
+ this.requestUpdate();
53
81
  }
54
82
 
55
- #render(): void {
56
- // Disabled until https://crbug.com/1079231 is fixed.
57
- // clang-format off
58
- render(html`
59
- <style>${reportingApiGridStyles}</style>
60
- <style>${UI.inspectorCommonStyles}</style>
61
- <div class="reporting-container" jslog=${VisualLogging.section('endpoints')}>
62
- <div class="reporting-header">${i18n.i18n.lockedString('Endpoints')}</div>
63
- ${this.#endpoints.size > 0 ? html`
64
- <devtools-data-grid striped>
65
- <table>
66
- <tr>
67
- <th id="origin" weight="30">${i18n.i18n.lockedString('Origin')}</th>
68
- <th id="name" weight="20">${i18n.i18n.lockedString('Name')}</th>
69
- <th id="url" weight="30">${i18n.i18n.lockedString('URL')}</th>
70
- </tr>
71
- ${Array.from(this.#endpoints).map(([origin, endpointArray]) =>
72
- endpointArray.map(endpoint => html`<tr>
73
- <td>${origin}</td>
74
- <td>${endpoint.groupName}</td>
75
- <td>${endpoint.url}</td>
76
- </tr>`))
77
- .flat()}
78
- </table>
79
- </devtools-data-grid>
80
- ` : html`
81
- <div class="empty-state">
82
- <span class="empty-state-header">${i18nString(UIStrings.noEndpointsToDisplay)}</span>
83
- <span class="empty-state-description">${i18nString(UIStrings.endpointsDescription)}</span>
84
- </div>
85
- `}
86
- </div>
87
- `, this.#shadow, {host: this});
88
- // clang-format on
89
- }
90
- }
91
-
92
- customElements.define('devtools-resources-endpoints-grid', EndpointsGrid);
93
-
94
- declare global {
95
- interface HTMLElementTagNameMap {
96
- 'devtools-resources-endpoints-grid': EndpointsGrid;
83
+ override performUpdate(): void {
84
+ this.#view(
85
+ {
86
+ endpoints: this.endpoints,
87
+ },
88
+ undefined, this.contentElement);
97
89
  }
98
90
  }
@@ -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
+ }