Skip to content

Commit 346f3df

Browse files
pfaffeDevtools-frontend LUCI CQ
authored andcommitted
Add throttling indications in the performance panel
Fixed: 444371867 Change-Id: Idd510e1bc78a19310cbc9464704e25198eecabd0 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7079393 Reviewed-by: Eric Leese <[email protected]> Commit-Queue: Philip Pfaffe <[email protected]>
1 parent a000135 commit 346f3df

File tree

5 files changed

+105
-3
lines changed

5 files changed

+105
-3
lines changed

front_end/panels/timeline/components/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ devtools_ui_module("unittests") {
125125
"LiveMetricsView.test.ts",
126126
"MetricCard.test.ts",
127127
"NetworkRequestDetails.test.ts",
128+
"NetworkRequestTooltip.test.ts",
128129
"NetworkThrottlingSelector.test.ts",
129130
"OriginMap.test.ts",
130131
"RelatedInsightChips.test.ts",
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2025 The Chromium Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import * as SDK from '../../../core/sdk/sdk.js';
6+
import * as Protocol from '../../../generated/protocol.js';
7+
import * as Trace from '../../../models/trace/trace.js';
8+
import {assertScreenshot, renderElementIntoDOM} from '../../../testing/DOMHelpers.js';
9+
import {describeWithMockConnection} from '../../../testing/MockConnection.js';
10+
11+
import * as TimelineComponents from './components.js';
12+
13+
describeWithMockConnection('NetworkRequestTooltip', () => {
14+
it('shows a throttling indicator', async () => {
15+
const networkRequest = sinon.createStubInstance(SDK.NetworkRequest.NetworkRequest);
16+
sinon.stub(SDK.TraceObject.RevealableNetworkRequest, 'create')
17+
.returns(new SDK.TraceObject.RevealableNetworkRequest(networkRequest));
18+
sinon.stub(SDK.NetworkManager.MultitargetNetworkManager.instance(), 'appliedRequestConditions').returns({
19+
conditions: SDK.NetworkManager.Slow3GConditions,
20+
urlPattern: 'https://example.com',
21+
});
22+
const tooltip = new TimelineComponents.NetworkRequestTooltip.NetworkRequestTooltip();
23+
renderElementIntoDOM(tooltip, {includeCommonStyles: true});
24+
const data: TimelineComponents.NetworkRequestTooltip.NetworkTooltipData = {
25+
networkRequest: {
26+
ts: 0,
27+
dur: 120,
28+
args: {
29+
data: {
30+
syntheticData: {sendStartTime: 100},
31+
url: 'https://example.com',
32+
mimeType: Protocol.Network.ResourceType.Document,
33+
redirects: []
34+
}
35+
}
36+
} as unknown as Trace.Types.Events.SyntheticNetworkRequest,
37+
entityMapper: sinon.createStubInstance(Trace.EntityMapper.EntityMapper),
38+
};
39+
tooltip.data = data;
40+
41+
await assertScreenshot('timeline/network-request-tooltip-throttling.png');
42+
});
43+
});

front_end/panels/timeline/components/NetworkRequestTooltip.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import '../../../ui/components/icon_button/icon_button.js';
77

88
import * as i18n from '../../../core/i18n/i18n.js';
99
import * as Platform from '../../../core/platform/platform.js';
10+
import * as SDK from '../../../core/sdk/sdk.js';
1011
import * as Trace from '../../../models/trace/trace.js';
1112
import * as PerfUI from '../../../ui/legacy/components/perf_ui/perf_ui.js';
1213
import * as Lit from '../../../ui/lit/lit.js';
@@ -15,7 +16,7 @@ import * as TimelineUtils from '../utils/utils.js';
1516
import networkRequestTooltipStyles from './networkRequestTooltip.css.js';
1617
import {colorForNetworkRequest, networkResourceCategory} from './Utils.js';
1718

18-
const {html} = Lit;
19+
const {html, nothing, Directives: {classMap, ifDefined}} = Lit;
1920

2021
const MAX_URL_LENGTH = 60;
2122

@@ -52,6 +53,11 @@ const UIStrings = {
5253
* @description Text to refer to the list of redirects.
5354
*/
5455
redirects: 'Redirects',
56+
/**
57+
* @description Cell title in Network Data Grid Node of the Network panel
58+
* @example {Fast 4G} PH1
59+
*/
60+
wasThrottled: 'Request was throttled ({PH1})',
5561
} as const;
5662
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/NetworkRequestTooltip.ts', UIStrings);
5763
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -106,6 +112,16 @@ export class NetworkRequestTooltip extends HTMLElement {
106112
backgroundColor: color,
107113
};
108114

115+
const sdkNetworkRequest = SDK.TraceObject.RevealableNetworkRequest.create(networkRequest);
116+
const wasThrottled = sdkNetworkRequest &&
117+
SDK.NetworkManager.MultitargetNetworkManager.instance().appliedRequestConditions(
118+
sdkNetworkRequest.networkRequest);
119+
const throttledTitle = wasThrottled ? i18nString(UIStrings.wasThrottled, {
120+
PH1: typeof wasThrottled.conditions.title === 'string' ? wasThrottled.conditions.title :
121+
wasThrottled.conditions.title()
122+
}) :
123+
undefined;
124+
109125
// The outside spans are transparent with a border on the outside edge.
110126
// The inside spans are 1px tall rectangles, vertically centered, with background color.
111127
// |
@@ -114,9 +130,20 @@ export class NetworkRequestTooltip extends HTMLElement {
114130
const leftWhisker = html`<span class="whisker-left"> <span class="horizontal"></span> </span>`;
115131
const rightWhisker = html`<span class="whisker-right"> <span class="horizontal"></span> </span>`;
116132

133+
const classes = classMap({
134+
['timings-row timings-row--duration']: true,
135+
throttled: Boolean(wasThrottled?.urlPattern),
136+
});
117137
return html`
118-
<div class="timings-row timings-row--duration">
119-
<span class="indicator"></span>
138+
<div
139+
class=${classes}
140+
title=${ifDefined(throttledTitle)}>
141+
${
142+
wasThrottled?.urlPattern ? html`<devtools-icon
143+
class=indicator
144+
name=watch
145+
></devtools-icon>` :
146+
html`<span class="indicator"></span>`}
120147
${i18nString(UIStrings.duration)}
121148
<span class="time"> ${i18n.TimeUtilities.formatMicroSecondsTime(networkRequest.dur)} </span>
122149
</div>
@@ -173,6 +200,11 @@ export class NetworkRequestTooltip extends HTMLElement {
173200

174201
const redirectsHtml = NetworkRequestTooltip.renderRedirects(this.#data.networkRequest);
175202

203+
const sdkNetworkRequest = SDK.TraceObject.RevealableNetworkRequest.create(this.#data.networkRequest);
204+
const wasThrottled = sdkNetworkRequest &&
205+
SDK.NetworkManager.MultitargetNetworkManager.instance().appliedRequestConditions(
206+
sdkNetworkRequest.networkRequest);
207+
176208
// clang-format off
177209
const output = html`
178210
<style>${networkRequestTooltipStyles}</style>
@@ -186,6 +218,13 @@ export class NetworkRequestTooltip extends HTMLElement {
186218
</span>${networkResourceCategory(this.#data.networkRequest)}
187219
</div>
188220
<div class="priority-row">${i18nString(UIStrings.priority)}: ${NetworkRequestTooltip.renderPriorityValue(this.#data.networkRequest)}</div>
221+
${wasThrottled ? html`
222+
<div class="throttled-row">
223+
${i18nString(UIStrings.wasThrottled, {
224+
PH1: typeof wasThrottled.conditions.title === 'string' ? wasThrottled.conditions.title :
225+
wasThrottled.conditions.title()
226+
})}
227+
</div>` : nothing}
189228
${Trace.Helpers.Network.isSyntheticNetworkRequestEventRenderBlocking(this.#data.networkRequest) ?
190229
html`<div class="render-blocking"> ${i18nString(UIStrings.renderBlocking)} </div>` : Lit.nothing
191230
}

front_end/panels/timeline/components/networkRequestTooltip.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
margin-left: 15px;
2323
}
2424

25+
.throttled-row {
26+
margin-left: 15px;
27+
color: var(--sys-color-yellow);
28+
}
29+
2530
.network-category-chip {
2631
box-sizing: border-box;
2732
width: 10px;
@@ -62,6 +67,16 @@
6267
box-sizing: border-box;
6368
}
6469

70+
devtools-icon.indicator {
71+
vertical-align: middle;
72+
height: 12px;
73+
width: 12px;
74+
margin-right: 4px;
75+
color: var(--sys-color-yellow);
76+
border: none;
77+
}
78+
79+
6580
.whisker-left {
6681
align-self: center;
6782
display: inline-flex;
@@ -104,6 +119,10 @@
104119
.time {
105120
font-weight: var(--ref-typeface-weight-medium);
106121
}
122+
123+
&.throttled {
124+
color: var(--sys-color-yellow);
125+
}
107126
}
108127

109128
.redirects-row {
13.1 KB
Loading

0 commit comments

Comments
 (0)