Skip to content

Commit f705a3f

Browse files
ktranDevtools-frontend LUCI CQ
authored andcommitted
[GM3Restyling] Update network panel empty state
Screenshot: https://imgur.com/a/J7xqnyn Bug: 325443331 Change-Id: I992d4b84448df83d32ea9995fb4b7b4aa8cb568e Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6278508 Commit-Queue: Kim-Anh Tran <[email protected]> Reviewed-by: Kateryna Prokopenko <[email protected]>
1 parent 83c2c29 commit f705a3f

File tree

6 files changed

+150
-73
lines changed

6 files changed

+150
-73
lines changed

front_end/panels/network/NetworkLogView.test.ts

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ import {
1616
getMenuItemLabels,
1717
} from '../../testing/ContextMenuHelpers.js';
1818
import {
19+
dispatchClickEvent,
1920
dispatchMouseUpEvent,
2021
raf,
2122
} from '../../testing/DOMHelpers.js';
22-
import {createTarget} from '../../testing/EnvironmentHelpers.js';
23+
import {createTarget, registerNoopActions, stubNoopSettings} from '../../testing/EnvironmentHelpers.js';
2324
import {expectCalled} from '../../testing/ExpectStubCall.js';
2425
import {stubFileManager} from '../../testing/FileManagerHelpers.js';
2526
import {describeWithMockConnection, dispatchEvent} from '../../testing/MockConnection.js';
@@ -52,6 +53,8 @@ describeWithMockConnection('NetworkLogView', () => {
5253
globalStorage: dummyStorage,
5354
localStorage: dummyStorage,
5455
});
56+
registerNoopActions(['network.toggle-recording', 'inspector-main.reload']);
57+
5558
sinon.stub(UI.ShortcutRegistry.ShortcutRegistry, 'instance').returns({
5659
shortcutTitleForAction: () => {},
5760
shortcutsForAction: () => [],
@@ -176,16 +179,6 @@ describeWithMockConnection('NetworkLogView', () => {
176179
);
177180
});
178181

179-
function createNetworkLogView(filterBar?: UI.FilterBar.FilterBar): Network.NetworkLogView.NetworkLogView {
180-
if (!filterBar) {
181-
filterBar = {addFilter: () => {}, filterButton: () => ({addEventListener: () => {}}), addDivider: () => {}} as
182-
unknown as UI.FilterBar.FilterBar;
183-
}
184-
return new Network.NetworkLogView.NetworkLogView(
185-
filterBar, document.createElement('div'),
186-
Common.Settings.Settings.instance().createSetting('network-log-large-rows', false));
187-
}
188-
189182
const tests = (inScope: boolean) => () => {
190183
beforeEach(() => {
191184
networkLogView = createNetworkLogView();
@@ -901,6 +894,76 @@ Invoke-WebRequest -UseBasicParsing -Uri "url-header-und-content-overridden"`]);
901894
});
902895
});
903896

897+
describeWithMockConnection('NetworkLogView placeholder', () => {
898+
const START_RECORDING_ID = 'network.toggle-recording';
899+
const RELOAD_ID = 'inspector-main.reload';
900+
901+
beforeEach(() => {
902+
stubNoopSettings();
903+
UI.ActionRegistration.registerActionExtension({
904+
actionId: START_RECORDING_ID,
905+
category: UI.ActionRegistration.ActionCategory.NETWORK,
906+
title: () => 'mock' as Platform.UIString.LocalizedString,
907+
toggleable: true,
908+
});
909+
UI.ActionRegistration.registerActionExtension({
910+
actionId: RELOAD_ID,
911+
category: UI.ActionRegistration.ActionCategory.NETWORK,
912+
title: () => 'mock' as Platform.UIString.LocalizedString,
913+
toggleable: true,
914+
});
915+
sinon.stub(UI.ShortcutRegistry.ShortcutRegistry, 'instance').returns({
916+
shortcutTitleForAction: () => 'Ctrl',
917+
shortcutsForAction: () => [new UI.KeyboardShortcut.KeyboardShortcut(
918+
[{key: UI.KeyboardShortcut.Keys.Ctrl.code, name: 'Ctrl'}], '', UI.KeyboardShortcut.Type.DEFAULT_SHORTCUT)],
919+
} as unknown as UI.ShortcutRegistry.ShortcutRegistry);
920+
});
921+
922+
it('shows instruction to start recording', async () => {
923+
const networkLogView = createNetworkLogView();
924+
testPlaceholderText(
925+
networkLogView, 'No network activity recorded',
926+
'Record network log to display network activity by using the \"Start recording\" button or by hitting Ctrl.');
927+
testPlaceholderButton(networkLogView, 'Start recording', START_RECORDING_ID);
928+
});
929+
930+
it('shows placeholder with instruction to reload page if already recording', async () => {
931+
const networkLogView = createNetworkLogView();
932+
networkLogView.setRecording(true);
933+
934+
testPlaceholderText(
935+
networkLogView, 'Currently recording network activity',
936+
'Perform a request or reload the page by using the \"Reload page\" button or by hitting Ctrl.');
937+
testPlaceholderButton(networkLogView, 'Reload page', RELOAD_ID);
938+
});
939+
});
940+
941+
function testPlaceholderText(
942+
networkLogView: Network.NetworkLogView.NetworkLogView, expectedHeaderText: string,
943+
expectedDescriptionText: string) {
944+
const emptyWidget = networkLogView.element.querySelector('.empty-state');
945+
946+
const header = emptyWidget?.querySelector('.empty-state-header')?.textContent;
947+
const description = emptyWidget?.querySelector('.empty-state-description > span')?.textContent;
948+
949+
assert.deepEqual(header, expectedHeaderText);
950+
assert.deepEqual(description, expectedDescriptionText);
951+
}
952+
953+
function testPlaceholderButton(
954+
networkLogView: Network.NetworkLogView.NetworkLogView, expectedButtonText: string, actionId: string) {
955+
const button = networkLogView.element.querySelector('.empty-state devtools-button');
956+
assert.exists(button);
957+
assert.deepEqual(button.textContent, expectedButtonText);
958+
959+
const action = UI.ActionRegistry.ActionRegistry.instance().getAction(actionId);
960+
const spy = sinon.spy(action, 'execute');
961+
962+
assert.isTrue(spy.notCalled);
963+
dispatchClickEvent(button);
964+
assert.isTrue(spy.calledOnce);
965+
}
966+
904967
function clickCheckbox(checkbox: HTMLInputElement) {
905968
checkbox.checked = true;
906969
const event = new Event('change');
@@ -955,3 +1018,13 @@ async function selectMoreFiltersOption(softMenu: HTMLElement, option: string) {
9551018
dispatchMouseUpEvent(item);
9561019
await raf();
9571020
}
1021+
1022+
function createNetworkLogView(filterBar?: UI.FilterBar.FilterBar): Network.NetworkLogView.NetworkLogView {
1023+
if (!filterBar) {
1024+
filterBar = {addFilter: () => {}, filterButton: () => ({addEventListener: () => {}}), addDivider: () => {}} as
1025+
unknown as UI.FilterBar.FilterBar;
1026+
}
1027+
return new Network.NetworkLogView.NetworkLogView(
1028+
filterBar, document.createElement('div'),
1029+
Common.Settings.Settings.instance().createSetting('network-log-large-rows', false));
1030+
}

front_end/panels/network/NetworkLogView.ts

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
4949
import * as NetworkForward from '../../panels/network/forward/forward.js';
5050
import * as Sources from '../../panels/sources/sources.js';
5151
import * as Adorners from '../../ui/components/adorners/adorners.js';
52+
import * as Buttons from '../../ui/components/buttons/buttons.js';
5253
import * as RenderCoordinator from '../../ui/components/render_coordinator/render_coordinator.js';
5354
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
5455
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
@@ -135,25 +136,40 @@ const UIStrings = {
135136
*/
136137
dropHarFilesHere: 'Drop HAR files here',
137138
/**
138-
*@description Recording text text content in Network Log View of the Network panel
139+
*@description Recording text content in Network Log View of the Network panel
139140
*/
140-
recordingNetworkActivity: 'Recording network activity',
141+
recordingNetworkActivity: 'Currently recording network activity',
141142
/**
142-
*@description Text in Network Log View of the Network panel
143-
*@example {Ctrl + R} PH1
143+
*@description Shown in the Network Log View of the Network panel when the user has not yet
144+
* recorded any network activity. This is an instruction to the user to reload the page in order to
145+
* show network activity in the current UI.
146+
*@example {Reload page} PH1
147+
*@example {Ctrl + R} PH2
144148
*/
145-
performARequestOrHitSToRecordThe: 'Perform a request or hit {PH1} to record the reload.',
149+
performARequestOrHitSToRecordThe:
150+
'Perform a request or reload the page by using the "{PH1}" button or by hitting {PH2}.',
146151
/**
147152
*@description Shown in the Network Log View of the Network panel when the user has not yet
148153
* recorded any network activity. This is an instruction to the user to start recording in order to
149154
* show network activity in the current UI.
150-
*@example {Ctrl + E} PH1
155+
* @example {Start recording} PH1
156+
* @example {Ctrl + E} PH2
157+
*/
158+
recordToDisplayNetworkActivity:
159+
'Record network log to display network activity by using the "{PH1}" button or by hitting {PH2}.',
160+
/**
161+
*@description Label of a button in the Network Log View of the Network panel.
151162
*/
152-
recordToDisplayNetworkActivity: 'Record network log ({PH1}) to display network activity.',
163+
reloadPage: 'Reload page',
153164
/**
154-
*@description Text that is usually a hyperlink to more documentation
165+
*@description Label of a button in the Network Log View of the Network panel.
155166
*/
156-
learnMore: 'Learn more',
167+
startRecording: 'Start recording',
168+
/**
169+
*@description Shown in the Network Log View of the Network panel when the user has not yet
170+
* recorded any network activity.
171+
*/
172+
noNetworkActivityRecorded: 'No network activity recorded',
157173
/**
158174
*@description Text to announce to screen readers that network data is available.
159175
*/
@@ -482,7 +498,7 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
482498
private filters: Filter[];
483499
private timeFilter: Filter|null;
484500
private hoveredNodeInternal: NetworkNode|null;
485-
private recordingHint: Element|null;
501+
private recordingHint: UI.EmptyWidget.EmptyWidget|null;
486502
private highlightedNode: NetworkRequestNode|null;
487503
private readonly linkifierInternal: Components.Linkifier.Linkifier;
488504
private recording: boolean;
@@ -1078,47 +1094,43 @@ export class NetworkLogView extends Common.ObjectWrapper.eventMixin<EventTypes,
10781094

10791095
private showRecordingHint(): void {
10801096
this.hideRecordingHint();
1081-
this.recordingHint = this.element.createChild('div', 'network-status-pane fill');
1082-
const hintText = this.recordingHint.createChild('div', 'recording-hint');
1083-
1084-
if (this.recording) {
1085-
let reloadShortcutNode: Element|null = null;
1086-
const reloadShortcut =
1087-
UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutsForAction('inspector-main.reload')[0];
1088-
if (reloadShortcut) {
1089-
reloadShortcutNode = this.recordingHint.createChild('b');
1090-
reloadShortcutNode.textContent = reloadShortcut.title();
1091-
}
10921097

1093-
const recordingText = hintText.createChild('span');
1094-
recordingText.textContent = i18nString(UIStrings.recordingNetworkActivity);
1095-
if (reloadShortcutNode) {
1096-
hintText.createChild('br');
1097-
hintText.appendChild(i18n.i18n.getFormatLocalizedString(
1098-
str_, UIStrings.performARequestOrHitSToRecordThe, {PH1: reloadShortcutNode}));
1099-
}
1100-
} else {
1101-
const recordNode = hintText.createChild('b');
1102-
recordNode.textContent =
1103-
UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutTitleForAction('network.toggle-recording') || '';
1104-
hintText.appendChild(
1105-
i18n.i18n.getFormatLocalizedString(str_, UIStrings.recordToDisplayNetworkActivity, {PH1: recordNode}));
1106-
}
1107-
hintText.createChild('br');
1108-
hintText.appendChild(UI.XLink.XLink.create(
1109-
'https://developer.chrome.com/docs/devtools/network/?utm_source=devtools&utm_campaign=2019Q1',
1110-
i18nString(UIStrings.learnMore), undefined, undefined, 'learn-more'));
1098+
const actionName = this.recording ? 'inspector-main.reload' : 'network.toggle-recording';
1099+
const action = UI.ActionRegistry.ActionRegistry.instance().getAction(actionName);
1100+
const shortcutTitle = UI.ShortcutRegistry.ShortcutRegistry.instance().shortcutTitleForAction(actionName) ?? '';
1101+
1102+
const header = this.recording ? i18nString(UIStrings.recordingNetworkActivity) :
1103+
i18nString(UIStrings.noNetworkActivityRecorded);
1104+
const instruction =
1105+
this.recording ? UIStrings.performARequestOrHitSToRecordThe : UIStrings.recordToDisplayNetworkActivity;
1106+
const buttonText = this.recording ? i18nString(UIStrings.reloadPage) : i18nString(UIStrings.startRecording);
1107+
// eslint-disable-next-line rulesdir/l10n-i18nString-call-only-with-uistrings
1108+
const description = i18nString(instruction, {
1109+
PH1: buttonText,
1110+
PH2: shortcutTitle,
1111+
});
11111112

1113+
this.recordingHint = new UI.EmptyWidget.EmptyWidget(header, shortcutTitle ? description : '');
1114+
this.recordingHint.element.classList.add('network-status-pane');
1115+
this.recordingHint.appendLink(
1116+
'https://developer.chrome.com/docs/devtools/network/' as Platform.DevToolsPath.UrlString);
1117+
const button = UI.UIUtils.createTextButton(buttonText, () => action.execute(), {
1118+
jslogContext: actionName,
1119+
variant: Buttons.Button.Variant.TONAL,
1120+
});
1121+
this.recordingHint.contentElement.appendChild(button);
1122+
1123+
this.recordingHint.show(this.element);
11121124
this.setHidden(true);
11131125
}
11141126

11151127
private hideRecordingHint(): void {
11161128
this.setHidden(false);
11171129
if (this.recordingHint) {
1118-
this.recordingHint.remove();
1130+
this.recordingHint.detach();
1131+
this.recordingHint = null;
11191132
}
11201133
UI.ARIAUtils.alert(i18nString(UIStrings.networkDataAvailable));
1121-
this.recordingHint = null;
11221134
}
11231135

11241136
private setHidden(value: boolean): void {

front_end/panels/network/NetworkPanel.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as Common from '../../core/common/common.js';
66
import * as SDK from '../../core/sdk/sdk.js';
77
import * as Logs from '../../models/logs/logs.js';
88
import * as Trace from '../../models/trace/trace.js';
9-
import {createTarget} from '../../testing/EnvironmentHelpers.js';
9+
import {createTarget, registerNoopActions} from '../../testing/EnvironmentHelpers.js';
1010
import {describeWithMockConnection} from '../../testing/MockConnection.js';
1111
import {createNetworkPanelForMockConnection} from '../../testing/NetworkHelpers.js';
1212
import * as RenderCoordinator from '../../ui/components/render_coordinator/render_coordinator.js';
@@ -66,6 +66,7 @@ describeWithMockConnection('NetworkPanel', () => {
6666
let networkPanel: Network.NetworkPanel.NetworkPanel;
6767

6868
beforeEach(async () => {
69+
registerNoopActions(['inspector-main.reload']);
6970
UI.ActionRegistration.maybeRemoveActionExtension('network.toggle-recording');
7071
UI.ActionRegistration.maybeRemoveActionExtension('network.clear');
7172
await import('./network-meta.js');

front_end/panels/network/networkLogView.css

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -328,23 +328,13 @@
328328
}
329329

330330
.network-status-pane {
331-
color: var(--sys-color-token-subtle);
331+
position: absolute;
332+
inset: 0;
332333
background-color: var(--sys-color-cdt-base-container);
333334
z-index: 500;
334-
display: flex;
335-
justify-content: center;
336-
align-items: center;
337-
text-align: center;
338-
padding: 0 20px;
339335
overflow: auto;
340336
}
341337

342-
.network-status-pane > .recording-hint {
343-
font-size: 14px;
344-
text-align: center;
345-
line-height: 28px;
346-
}
347-
348338
.network-waterfall-header {
349339
position: absolute;
350340
border-left: 0;
@@ -422,10 +412,6 @@
422412
}
423413

424414
@media (forced-colors: active) {
425-
.network-status-pane > .recording-hint {
426-
color: canvastext;
427-
}
428-
429415
.initiator-column .devtools-link {
430416
color: linktext;
431417
}
@@ -448,8 +434,8 @@
448434
--color-grid-focus-selected: Highlight;
449435
}
450436

451-
#network-container.no-node-selected:focus-within,
452-
.network-status-pane {
437+
#network-container.no-node-selected:focus-within
438+
{
453439
forced-color-adjust: none;
454440
border-color: Highlight;
455441
background-color: canvas !important; /* stylelint-disable-line declaration-no-important */

front_end/testing/NetworkHelpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from './EnvironmentHelpers.js';
1212

1313
export async function createNetworkPanelForMockConnection(): Promise<Network.NetworkPanel.NetworkPanel> {
14-
registerNoopActions(['network.toggle-recording', 'network.clear']);
14+
registerNoopActions(['network.toggle-recording', 'network.clear', 'inspector-main.reload']);
1515

1616
const dummyStorage = new Common.Settings.SettingsStorage({});
1717
for (const settingName

test/e2e/helpers/network-helpers.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,12 @@ export function veImpressionForNetworkPanel(options?: {newFilterBar?: boolean})
219219
]),
220220
veImpression('Timeline', 'network-overview'),
221221
veImpression('Toggle', 'network-settings'),
222-
veImpression('Link', 'learn-more'),
222+
veImpression(
223+
'Section', 'empty-view',
224+
[
225+
veImpression('Action', 'inspector-main.reload'),
226+
veImpression('Link', 'learn-more'),
227+
]),
223228
veImpression('TableHeader', 'name'),
224229
veImpression('TableHeader', 'status'),
225230
veImpression('TableHeader', 'type'),

0 commit comments

Comments
 (0)