Skip to content

Commit 4e5dc51

Browse files
ktranDevtools-frontend LUCI CQ
authored andcommitted
[GM3Restyling] Introduce new empty state for ReportingAPI
This adds another placeholder to reporting api, in case neither report nor endpoint have yet been detected. Before: https://i.imgur.com/2OyzfZh.png After: https://i.imgur.com/mCl5UAQ.png Bug: 400383914 Change-Id: If59cbdd755a34072afecc5ad6956f546173b40bf Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6342615 Reviewed-by: Ergün Erdoğmuş <[email protected]> Commit-Queue: Kim-Anh Tran <[email protected]>
1 parent 04cb086 commit 4e5dc51

File tree

2 files changed

+101
-3
lines changed

2 files changed

+101
-3
lines changed

front_end/panels/application/ReportingApiView.test.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// found in the LICENSE file.
44

55
import * as SDK from '../../core/sdk/sdk.js';
6+
import * as Protocol from '../../generated/protocol.js';
67
import {createTarget} from '../../testing/EnvironmentHelpers.js';
78
import {describeWithMockConnection} from '../../testing/MockConnection.js';
89
import * as UI from '../../ui/legacy/legacy.js';
@@ -38,15 +39,64 @@ describeWithMockConnection('ReportingApiView', () => {
3839
endpointsGridData.set, {endpoints: new Map([[ORIGIN_1, ENDPOINTS_1], [ORIGIN_2, ENDPOINTS_2]])});
3940
});
4041

41-
it('shows reports (main element) and endpoints (sidebar element)', () => {
42+
it('shows placeholder if no report or endpoint data is available yet', () => {
4243
const target = createTarget();
4344
const networkManager = target.model(SDK.NetworkManager.NetworkManager);
4445
assert.exists(networkManager);
4546
const endpointsGrid = new ApplicationComponents.EndpointsGrid.EndpointsGrid();
4647
const view = new Application.ReportingApiView.ReportingApiView(endpointsGrid);
4748

49+
assert.exists(view.element.querySelector('.empty-state'));
50+
assert.deepEqual(view.element.querySelector('.empty-state-header')?.textContent, 'No report or endpoint');
51+
assert.deepEqual(
52+
view.element.querySelector('.empty-state-description > span')?.textContent,
53+
'On this page you will be able to inspect Reporting API reports and endpoints.');
54+
});
55+
56+
it('shows reports (main element) and endpoints (sidebar element) if endpoint appears', () => {
57+
const target = createTarget();
58+
const networkManager = target.model(SDK.NetworkManager.NetworkManager);
59+
assert.exists(networkManager);
60+
const endpointsGrid = new ApplicationComponents.EndpointsGrid.EndpointsGrid();
61+
const view = new Application.ReportingApiView.ReportingApiView(endpointsGrid);
62+
63+
networkManager.dispatchEventToListeners(
64+
SDK.NetworkManager.Events.ReportingApiEndpointsChangedForOrigin, {origin: 'dummy', endpoints: []});
65+
assert.isTrue(view.showMode() === UI.SplitWidget.ShowMode.BOTH);
66+
assert.isNotNull(view.mainWidget());
67+
assert.instanceOf(view.mainWidget(), Application.ReportingApiReportsView.ReportingApiReportsView);
68+
assert.isNotNull(view.sidebarElement());
69+
});
70+
71+
it('shows reports (main element) and endpoints (sidebar element) if report appears', () => {
72+
const target = createTarget();
73+
const networkManager = target.model(SDK.NetworkManager.NetworkManager);
74+
assert.exists(networkManager);
75+
const endpointsGrid = new ApplicationComponents.EndpointsGrid.EndpointsGrid();
76+
const view = new Application.ReportingApiView.ReportingApiView(endpointsGrid);
77+
78+
const report = {
79+
id: 'some_id' as Protocol.Network.ReportId,
80+
initiatorUrl: 'https://example.com/script.js',
81+
destination: 'main-endpoint',
82+
type: 'deprecation',
83+
timestamp: 1,
84+
depth: 1,
85+
completedAttempts: 0,
86+
body: {
87+
columnNumber: 8,
88+
id: 'PrefixedStorageInfo',
89+
lineNumber: 15,
90+
message: '',
91+
sourceFile: 'https://example.com/script.js',
92+
},
93+
status: Protocol.Network.ReportStatus.Queued,
94+
};
95+
96+
networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.ReportingApiReportAdded, report);
4897
assert.isTrue(view.showMode() === UI.SplitWidget.ShowMode.BOTH);
4998
assert.isNotNull(view.mainWidget());
99+
assert.instanceOf(view.mainWidget(), Application.ReportingApiReportsView.ReportingApiReportsView);
50100
assert.isNotNull(view.sidebarElement());
51101
});
52102
});

front_end/panels/application/ReportingApiView.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import * as i18n from '../../core/i18n/i18n.js';
6+
import type * as Platform from '../../core/platform/platform.js';
57
import * as SDK from '../../core/sdk/sdk.js';
68
import type * as Protocol from '../../generated/protocol.js';
79
import * as UI from '../../ui/legacy/legacy.js';
@@ -10,9 +12,33 @@ import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
1012
import type * as ApplicationComponents from './components/components.js';
1113
import {ReportingApiReportsView} from './ReportingApiReportsView.js';
1214

15+
const UIStrings = {
16+
/**
17+
*@description Placeholder text that shows if no report or endpoint was detected.
18+
* A report contains information on issues or events that were encountered by a web browser.
19+
* An endpoint is a URL where the report is sent to.
20+
* (https://developer.chrome.com/docs/capabilities/web-apis/reporting-api)
21+
*/
22+
noReportOrEndpoint: 'No report or endpoint',
23+
/**
24+
*@description Placeholder text that shows if no report or endpoint was detected.
25+
* A report contains information on issues or events that were encountered by a web browser.
26+
* An endpoint is a URL where the report is sent to.
27+
* (https://developer.chrome.com/docs/capabilities/web-apis/reporting-api)
28+
*/
29+
reportingApiDescription: 'On this page you will be able to inspect `Reporting API` reports and endpoints.',
30+
} as const;
31+
const str_ = i18n.i18n.registerUIStrings('panels/application/ReportingApiView.ts', UIStrings);
32+
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
33+
34+
const REPORTING_API_EXPLANATION_URL =
35+
'https://developer.chrome.com/docs/capabilities/web-apis/reporting-api' as Platform.DevToolsPath.UrlString;
36+
1337
export class ReportingApiView extends UI.SplitWidget.SplitWidget {
1438
private readonly endpointsGrid: ApplicationComponents.EndpointsGrid.EndpointsGrid;
1539
private endpoints: Map<string, Protocol.Network.ReportingApiEndpoint[]>;
40+
#emptyWidget?: UI.EmptyWidget.EmptyWidget;
41+
#reportingApiReports?: ReportingApiReportsView;
1642

1743
constructor(endpointsGrid: ApplicationComponents.EndpointsGrid.EndpointsGrid) {
1844
super(/* isVertical: */ false, /* secondIsSidebar: */ true);
@@ -21,22 +47,44 @@ export class ReportingApiView extends UI.SplitWidget.SplitWidget {
2147
this.endpoints = new Map();
2248
const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
2349
const networkManager = mainTarget?.model(SDK.NetworkManager.NetworkManager);
50+
this.#emptyWidget = new UI.EmptyWidget.EmptyWidget(
51+
i18nString(UIStrings.noReportOrEndpoint), i18nString(UIStrings.reportingApiDescription));
52+
this.#emptyWidget.appendLink(REPORTING_API_EXPLANATION_URL);
53+
this.setMainWidget(this.#emptyWidget);
2454
if (networkManager) {
2555
networkManager.addEventListener(
2656
SDK.NetworkManager.Events.ReportingApiEndpointsChangedForOrigin,
2757
event => this.onEndpointsChangedForOrigin(event.data), this);
2858

29-
const reportingApiReportsView = new ReportingApiReportsView(networkManager);
59+
networkManager.addEventListener(
60+
SDK.NetworkManager.Events.ReportingApiReportAdded, this.#showReportsAndEndpoints, this);
61+
62+
this.#reportingApiReports = new ReportingApiReportsView(networkManager);
3063
const reportingApiEndpointsView = new UI.Widget.VBox();
3164
reportingApiEndpointsView.setMinimumSize(0, 40);
3265
reportingApiEndpointsView.contentElement.appendChild(this.endpointsGrid);
33-
this.setMainWidget(reportingApiReportsView);
66+
3467
this.setSidebarWidget(reportingApiEndpointsView);
3568
void networkManager.enableReportingApi();
69+
this.hideSidebar();
3670
}
3771
}
3872

73+
#showReportsAndEndpoints(): void {
74+
// Either we don't have reports and endpoints to show (first case), or we have already
75+
// replaced the empty widget with a different main view (second case).
76+
if (this.#reportingApiReports === undefined || this.mainWidget() !== this.#emptyWidget) {
77+
return;
78+
}
79+
80+
this.#emptyWidget?.detach();
81+
this.#emptyWidget = undefined;
82+
this.setMainWidget(this.#reportingApiReports);
83+
this.showBoth();
84+
}
85+
3986
private onEndpointsChangedForOrigin(data: Protocol.Network.ReportingApiEndpointsChangedForOriginEvent): void {
87+
this.#showReportsAndEndpoints();
4088
this.endpoints.set(data.origin, data.endpoints);
4189
this.endpointsGrid.data = {endpoints: this.endpoints};
4290
}

0 commit comments

Comments
 (0)