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.
- package/front_end/core/host/GdpClient.ts +116 -66
- package/front_end/core/root/Runtime.ts +1 -0
- package/front_end/entrypoints/inspector_main/InspectorMain.ts +82 -32
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -1
- package/front_end/entrypoints/main/MainImpl.ts +7 -1
- package/front_end/generated/InspectorBackendCommands.js +3 -2
- package/front_end/generated/protocol-mapping.d.ts +9 -0
- package/front_end/generated/protocol-proxy-api.d.ts +8 -0
- package/front_end/generated/protocol.ts +12 -0
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +10 -6
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +42 -4
- package/front_end/models/badges/UserBadges.ts +14 -16
- package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -2
- package/front_end/panels/application/IndexedDBViews.ts +1 -0
- package/front_end/panels/application/ReportingApiTreeElement.ts +1 -2
- package/front_end/panels/application/ReportingApiView.ts +18 -20
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -0
- package/front_end/panels/application/components/EndpointsGrid.ts +51 -59
- package/front_end/panels/application/components/ReportsGrid.ts +86 -107
- package/front_end/panels/application/components/StorageMetadataView.ts +30 -4
- package/front_end/panels/application/components/endpointsGrid.css +30 -0
- package/front_end/panels/application/components/reportsGrid.css +34 -0
- package/front_end/panels/application/components/storageMetadataView.css +9 -0
- package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +19 -27
- package/front_end/panels/common/BadgeNotification.ts +10 -3
- package/front_end/panels/network/NetworkPanel.ts +1 -1
- package/front_end/panels/search/SearchResultsPane.ts +14 -13
- package/front_end/panels/search/SearchView.ts +3 -20
- package/front_end/panels/settings/components/SyncSection.ts +8 -6
- package/front_end/panels/sources/SearchSourcesView.ts +1 -1
- package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -11
- package/front_end/panels/whats_new/resources/WNDT.md +9 -6
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/diff/README.chromium +0 -1
- package/front_end/ui/legacy/Treeoutline.ts +6 -9
- package/front_end/ui/legacy/UIUtils.ts +4 -17
- package/front_end/ui/legacy/Widget.ts +0 -5
- package/front_end/ui/legacy/XElement.ts +0 -33
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
- package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +38 -21
- package/front_end/ui/legacy/components/perf_ui/filmStripView.css +29 -0
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +3 -2
- package/front_end/ui/legacy/legacy.ts +0 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +1 -1
- package/front_end/panels/application/components/reportingApiGrid.css +0 -31
- package/front_end/ui/legacy/XWidget.ts +0 -133
@@ -5,10 +5,12 @@
|
|
5
5
|
import type * as SDK from '../../../core/sdk/sdk.js';
|
6
6
|
import * as Logs from '../../logs/logs.js';
|
7
7
|
import * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
|
8
|
+
import * as TextUtils from '../../text_utils/text_utils.js';
|
8
9
|
|
9
10
|
import {seconds} from './UnitFormatters.js';
|
10
11
|
|
11
12
|
const MAX_HEADERS_SIZE = 1000;
|
13
|
+
const MAX_BODY_SIZE = 10000;
|
12
14
|
|
13
15
|
/**
|
14
16
|
* Sanitizes the set of headers, removing values that are not on the allow-list and replacing them with '<redacted>'.
|
@@ -24,6 +26,8 @@ function sanitizeHeaders(headers: Array<{name: string, value: string}>): Array<{
|
|
24
26
|
|
25
27
|
export class NetworkRequestFormatter {
|
26
28
|
#calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
|
29
|
+
#request: SDK.NetworkRequest.NetworkRequest;
|
30
|
+
|
27
31
|
static allowHeader(headerName: string): boolean {
|
28
32
|
return allowedHeaders.has(headerName.toLowerCase().trim());
|
29
33
|
}
|
@@ -37,6 +41,31 @@ export class NetworkRequestFormatter {
|
|
37
41
|
MAX_HEADERS_SIZE);
|
38
42
|
}
|
39
43
|
|
44
|
+
static async formatBody(title: string, request: SDK.NetworkRequest.NetworkRequest, maxBodySize: number):
|
45
|
+
Promise<string> {
|
46
|
+
const data = await request.requestContentData();
|
47
|
+
|
48
|
+
if (TextUtils.ContentData.ContentData.isError(data)) {
|
49
|
+
return '';
|
50
|
+
}
|
51
|
+
|
52
|
+
if (data.isEmpty) {
|
53
|
+
return `${title}\n<empty response>`;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (data.isTextContent) {
|
57
|
+
const dataAsText = data.text;
|
58
|
+
|
59
|
+
if (dataAsText.length > maxBodySize) {
|
60
|
+
return `${title}\n${dataAsText.substring(0, maxBodySize) + '... <truncated>'}`;
|
61
|
+
}
|
62
|
+
|
63
|
+
return `${title}\n${dataAsText}`;
|
64
|
+
}
|
65
|
+
|
66
|
+
return `${title}\n<binary data>`;
|
67
|
+
}
|
68
|
+
|
40
69
|
static formatInitiatorUrl(initiatorUrl: string, allowedOrigin: string): string {
|
41
70
|
const initiatorOrigin = new URL(initiatorUrl).origin;
|
42
71
|
if (initiatorOrigin === allowedOrigin) {
|
@@ -45,8 +74,6 @@ export class NetworkRequestFormatter {
|
|
45
74
|
return '<redacted cross-origin initiator URL>';
|
46
75
|
}
|
47
76
|
|
48
|
-
#request: SDK.NetworkRequest.NetworkRequest;
|
49
|
-
|
50
77
|
constructor(
|
51
78
|
request: SDK.NetworkRequest.NetworkRequest, calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator) {
|
52
79
|
this.#request = request;
|
@@ -61,16 +88,27 @@ export class NetworkRequestFormatter {
|
|
61
88
|
return NetworkRequestFormatter.formatHeaders('Response headers:', this.#request.responseHeaders);
|
62
89
|
}
|
63
90
|
|
91
|
+
async formatResponseBody(): Promise<string> {
|
92
|
+
return await NetworkRequestFormatter.formatBody('Response body:', this.#request, MAX_BODY_SIZE);
|
93
|
+
}
|
94
|
+
|
64
95
|
/**
|
65
96
|
* Note: nothing here should include information from origins other than
|
66
97
|
* the request's origin.
|
67
98
|
*/
|
68
|
-
formatNetworkRequest(): string {
|
99
|
+
async formatNetworkRequest(): Promise<string> {
|
100
|
+
let responseBody = await this.formatResponseBody();
|
101
|
+
|
102
|
+
if (responseBody) {
|
103
|
+
// if we have a response then we add 2 new line to follow same structure of the context
|
104
|
+
responseBody = `\n\n${responseBody}`;
|
105
|
+
}
|
106
|
+
|
69
107
|
return `Request: ${this.#request.url()}
|
70
108
|
|
71
109
|
${this.formatRequestHeaders()}
|
72
110
|
|
73
|
-
${this.formatResponseHeaders()}
|
111
|
+
${this.formatResponseHeaders()}${responseBody}
|
74
112
|
|
75
113
|
Response status: ${this.#request.statusCode} ${this.#request.statusText}
|
76
114
|
|
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
6
6
|
import * as Host from '../../core/host/host.js';
|
7
|
-
import * as Root from '../../core/root/root.js';
|
8
7
|
|
9
8
|
import {AiExplorerBadge} from './AiExplorerBadge.js';
|
10
9
|
import type {Badge, BadgeAction, BadgeActionEvents, BadgeContext, TriggerOptions} from './Badge.js';
|
@@ -50,8 +49,7 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
50
49
|
super();
|
51
50
|
|
52
51
|
this.#receiveBadgesSetting = Common.Settings.Settings.instance().moduleSetting('receive-gdp-badges');
|
53
|
-
if (Host.GdpClient.
|
54
|
-
Root.Runtime.GdpProfilesEnterprisePolicyValue.ENABLED_WITHOUT_BADGES) {
|
52
|
+
if (!Host.GdpClient.isBadgesEnabled()) {
|
55
53
|
this.#receiveBadgesSetting.set(false);
|
56
54
|
}
|
57
55
|
this.#receiveBadgesSetting.addChangeListener(this.#reconcileBadges, this);
|
@@ -106,10 +104,10 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
106
104
|
if (!badge.isStarterBadge) {
|
107
105
|
shouldAwardBadge = true;
|
108
106
|
} else {
|
109
|
-
const
|
107
|
+
const getProfileResponse = await Host.GdpClient.GdpClient.instance().getProfile();
|
110
108
|
const receiveBadgesSettingEnabled = Boolean(this.#receiveBadgesSetting.get());
|
111
109
|
// If there is a GDP profile and the user has enabled receiving badges, we award the starter badge as well.
|
112
|
-
if (
|
110
|
+
if (getProfileResponse?.profile && receiveBadgesSettingEnabled && !this.#isStarterBadgeDismissed() &&
|
113
111
|
!this.#isStarterBadgeSnoozed()) {
|
114
112
|
shouldAwardBadge = true;
|
115
113
|
}
|
@@ -157,27 +155,28 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
157
155
|
return;
|
158
156
|
}
|
159
157
|
|
160
|
-
if (!Host.GdpClient.isGdpProfilesAvailable() ||
|
161
|
-
Host.GdpClient.getGdpProfilesEnterprisePolicy() !== Root.Runtime.GdpProfilesEnterprisePolicyValue.ENABLED) {
|
158
|
+
if (!Host.GdpClient.isGdpProfilesAvailable() || !Host.GdpClient.isBadgesEnabled()) {
|
162
159
|
this.#deactivateAllBadges();
|
163
160
|
return;
|
164
161
|
}
|
165
162
|
|
166
|
-
const
|
167
|
-
|
168
|
-
|
169
|
-
|
163
|
+
const getProfileResponse = await Host.GdpClient.GdpClient.instance().getProfile();
|
164
|
+
if (!getProfileResponse) {
|
165
|
+
this.#deactivateAllBadges();
|
166
|
+
return;
|
170
167
|
}
|
171
168
|
|
169
|
+
const hasGdpProfile = Boolean(getProfileResponse.profile);
|
170
|
+
const isEligibleToCreateProfile = getProfileResponse.isEligible;
|
172
171
|
// User does not have a GDP profile & not eligible to create one.
|
173
172
|
// So, we don't activate any badges for them.
|
174
|
-
if (!
|
173
|
+
if (!hasGdpProfile && !isEligibleToCreateProfile) {
|
175
174
|
this.#deactivateAllBadges();
|
176
175
|
return;
|
177
176
|
}
|
178
177
|
|
179
178
|
let awardedBadgeNames: Set<string>|null = null;
|
180
|
-
if (
|
179
|
+
if (hasGdpProfile) {
|
181
180
|
awardedBadgeNames = await Host.GdpClient.GdpClient.instance().getAwardedBadgeNames(
|
182
181
|
{names: this.#allBadges.map(badge => badge.name)});
|
183
182
|
// This is a conservative approach. We bail out if `awardedBadgeNames` is null
|
@@ -202,9 +201,8 @@ export class UserBadges extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
202
201
|
}
|
203
202
|
|
204
203
|
const shouldActivateStarterBadge = badge.isStarterBadge && isEligibleToCreateProfile &&
|
205
|
-
!this.#isStarterBadgeDismissed() && !this.#isStarterBadgeSnoozed();
|
206
|
-
const shouldActivateActivityBasedBadge =
|
207
|
-
!badge.isStarterBadge && Boolean(gdpProfile) && receiveBadgesSettingEnabled;
|
204
|
+
Host.GdpClient.isStarterBadgeEnabled() && !this.#isStarterBadgeDismissed() && !this.#isStarterBadgeSnoozed();
|
205
|
+
const shouldActivateActivityBasedBadge = !badge.isStarterBadge && hasGdpProfile && receiveBadgesSettingEnabled;
|
208
206
|
if (shouldActivateStarterBadge || shouldActivateActivityBasedBadge) {
|
209
207
|
badge.activate();
|
210
208
|
} else {
|
@@ -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
|
275
|
+
`, target);
|
277
276
|
// clang-format on
|
278
277
|
};
|
279
278
|
|
@@ -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(
|
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
|
-
|
54
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
162
|
-
|
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
|
-
|
188
|
-
const
|
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
|
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
|
32
|
+
export interface ViewInput {
|
34
33
|
endpoints: Map<string, Protocol.Network.ReportingApiEndpoint[]>;
|
35
34
|
}
|
36
35
|
|
37
|
-
export
|
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
|
-
|
40
|
-
#endpoints = new Map<string, Protocol.Network.ReportingApiEndpoint[]>();
|
71
|
+
type View = typeof DEFAULT_VIEW;
|
41
72
|
|
42
|
-
|
43
|
-
|
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
|
-
|
52
|
-
|
77
|
+
constructor(element?: HTMLElement, view: View = DEFAULT_VIEW) {
|
78
|
+
super(element);
|
79
|
+
this.#view = view;
|
80
|
+
this.requestUpdate();
|
53
81
|
}
|
54
82
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
}
|