Skip to content

Commit 3c18d9b

Browse files
Adam RaineDevtools-frontend LUCI CQ
authored andcommitted
[RPP] Add descriptive empty state for all insights
https://screenshot.googleplex.com/3q5TSi5QT9pomTL Bug: 382211674 Change-Id: I94493fdd4b7f04bd178ad86f07e07f1f97928a11 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6076300 Commit-Queue: Adam Raine <[email protected]> Reviewed-by: Jack Franklin <[email protected]>
1 parent 4359b77 commit 3c18d9b

File tree

8 files changed

+60
-6
lines changed

8 files changed

+60
-6
lines changed

front_end/panels/timeline/components/insights/CLSCulprits.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ const UIStrings = {
4747
* @description Text for a culprit type of Unsized images.
4848
*/
4949
unsizedImages: 'Unsized Images',
50+
/**
51+
* @description Text status when there were no layout shifts detected.
52+
*/
53+
noLayoutShifts: 'No layout shifts',
54+
/**
55+
* @description Text status when there no layout shifts culprits/root causes were found.
56+
*/
57+
noCulprits: 'Could not detect any layout shift culprits',
5058
};
5159
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/CLSCulprits.ts', UIStrings);
5260
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -131,7 +139,7 @@ export class CLSCulprits extends BaseInsightComponent<CLSCulpritsInsightModel> {
131139
}
132140

133141
if (!this.model.clusters.length || !this.model.worstCluster) {
134-
return LitHtml.nothing;
142+
return html`<div class="insight-section">${i18nString(UIStrings.noLayoutShifts)}</div>`;
135143
}
136144

137145
const worstCluster = this.model.worstCluster;
@@ -140,7 +148,7 @@ export class CLSCulprits extends BaseInsightComponent<CLSCulpritsInsightModel> {
140148
// TODO: getTopCulprits needs to move to model.
141149
const culprits = this.getTopCulprits(worstCluster, culpritsByShift);
142150
if (culprits.length === 0) {
143-
return LitHtml.nothing;
151+
return html`<div class="insight-section">${i18nString(UIStrings.noCulprits)}</div>`;
144152
}
145153

146154
const ts = Trace.Types.Timing.MicroSeconds(worstCluster.ts - this.bounds.min);

front_end/panels/timeline/components/insights/ImageDelivery.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ const UIStrings = {
2727
* @example {5} PH1
2828
*/
2929
others: '{PH1} others',
30+
/**
31+
* @description Text status indicating that no potential optimizations were found for any image file
32+
*/
33+
noOptimizableImages: 'No optimizable images',
3034
};
3135

3236
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/ImageDelivery.ts', UIStrings);
@@ -81,7 +85,7 @@ export class ImageDelivery extends BaseInsightComponent<ImageDeliveryInsightMode
8185
}
8286

8387
if (!rows.length) {
84-
return LitHtml.nothing;
88+
return html`<div class="insight-section">${i18nString(UIStrings.noOptimizableImages)}</div>`;
8589
}
8690

8791
// clang-format off

front_end/panels/timeline/components/insights/InteractionToNextPaint.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ const UIStrings = {
3838
*@description Text shown next to the interaction event's presentation delay time in the detail view.
3939
*/
4040
presentationDelay: 'Presentation delay',
41+
/**
42+
* @description Text status indicating that no user interactions were detected.
43+
*/
44+
noInteractions: 'No interactions detected',
4145
};
4246

4347
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/InteractionToNextPaint.ts', UIStrings);
@@ -97,7 +101,7 @@ export class InteractionToNextPaint extends BaseInsightComponent<INPInsightModel
97101
override renderContent(): LitHtml.LitTemplate {
98102
const event = this.model?.longestInteractionEvent;
99103
if (!event) {
100-
return LitHtml.nothing;
104+
return html`<div class="insight-section">${i18nString(UIStrings.noInteractions)}</div>`;
101105
}
102106

103107
const time = (us: Trace.Types.Timing.MicroSeconds): string =>

front_end/panels/timeline/components/insights/LCPDiscovery.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ const UIStrings = {
4343
*@example {Server response time} PH1
4444
*/
4545
failedAriaLabel: 'Insight check failed: {PH1}',
46+
/**
47+
* @description Text status indicating that the the Largest Contentful Paint (LCP) metric timing was not found. "LCP" is an acronym and should not be translated.
48+
*/
49+
noLcp: 'No LCP detected',
50+
/**
51+
* @description Text status indicating that the Largest Contentful Paint (LCP) metric was text rather than an image. "LCP" is an acronym and should not be translated.
52+
*/
53+
noLcpResource: 'No LCP resource detected because the LCP is not an image',
4654
};
4755

4856
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/LCPDiscovery.ts', UIStrings);
@@ -172,7 +180,10 @@ export class LCPDiscovery extends BaseInsightComponent<LCPDiscoveryInsightModel>
172180

173181
const imageData = getImageData(this.model);
174182
if (!imageData) {
175-
return LitHtml.nothing;
183+
if (!this.model.lcpEvent) {
184+
return html`<div class="insight-section">${i18nString(UIStrings.noLcp)}</div>`;
185+
}
186+
return html`<div class="insight-section">${i18nString(UIStrings.noLcpResource)}</div>`;
176187
}
177188

178189
// clang-format off

front_end/panels/timeline/components/insights/LCPPhases.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ const UIStrings = {
4040
*@description Label used for the percentage a single phase/component/stage/section takes up of a larger duration.
4141
*/
4242
percentLCP: '% of LCP',
43+
/**
44+
* @description Text status indicating that the the Largest Contentful Paint (LCP) metric timing was not found. "LCP" is an acronym and should not be translated.
45+
*/
46+
noLcp: 'No LCP detected',
4347
};
4448
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/LCPPhases.ts', UIStrings);
4549
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -192,6 +196,9 @@ export class LCPPhases extends BaseInsightComponent<LCPPhasesInsightModel> {
192196
}
193197

194198
const phaseData = this.#getPhaseData();
199+
if (!phaseData.length) {
200+
return html`<div class="insight-section">${i18nString(UIStrings.noLcp)}</div>`;
201+
}
195202

196203
const rows = phaseData.map(({phase, percent}) => {
197204
const section = this.#overlay?.sections.find(section => phase === section.label);

front_end/panels/timeline/components/insights/RenderBlocking.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ const UIStrings = {
2525
*@description Label used for a time duration.
2626
*/
2727
duration: 'Duration',
28+
/**
29+
* @description Text status indicating that no requests blocked the initial render of a navigation
30+
*/
31+
noRenderBlocking: 'No render blocking requests for this navigation',
2832
};
2933

3034
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/RenderBlocking.ts', UIStrings);
@@ -63,7 +67,7 @@ export class RenderBlocking extends BaseInsightComponent<RenderBlockingInsightMo
6367
const topRequests = this.model.renderBlockingRequests.slice(0, MAX_REQUESTS);
6468

6569
if (!topRequests.length) {
66-
return LitHtml.nothing;
70+
return html`<div class="insight-section">${i18nString(UIStrings.noRenderBlocking)}</div>`;
6771
}
6872

6973
// clang-format off

front_end/panels/timeline/components/insights/SlowCSSSelector.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ const UIStrings = {
4141
*@description Column name for a total sum.
4242
*/
4343
total: 'Total',
44+
/**
45+
* @description Text status indicating that no CSS selector data was found.
46+
*/
47+
enableSelectorData:
48+
'No CSS selector data was found. CSS selector stats need to be enabled in the performance panel settings.',
4449
};
4550

4651
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/SlowCSSSelector.ts', UIStrings);
@@ -126,6 +131,10 @@ export class SlowCSSSelector extends BaseInsightComponent<SlowCSSSelectorInsight
126131
const time = (us: Trace.Types.Timing.MicroSeconds): string =>
127132
i18n.TimeUtilities.millisToString(Platform.Timing.microSecondsToMilliSeconds(us));
128133

134+
if (!this.model.topMatchAttempts.length && !this.model.topElapsedMs.length) {
135+
return html`<div class="insight-section">${i18nString(UIStrings.enableSelectorData)}</div>`;
136+
}
137+
129138
// clang-format off
130139
const sections = [html`
131140
<div class="insight-section">

front_end/panels/timeline/components/insights/ThirdParties.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ const UIStrings = {
2222
columnTransferSize: 'Transfer size',
2323
/** Label for a table column that displays how much time each row spent blocking other work on the main thread, entries will be the number of milliseconds spent. */
2424
columnBlockingTime: 'Blocking time',
25+
/**
26+
* @description Text block indicating that no third party content was detected on the page
27+
*/
28+
noThirdParties: 'No third parties found',
2529
};
2630

2731
const str_ = i18n.i18n.registerUIStrings('panels/timeline/components/insights/ThirdParties.ts', UIStrings);
@@ -69,6 +73,9 @@ export class ThirdParties extends BaseInsightComponent<ThirdPartiesInsightModel>
6973
}
7074

7175
const entries = [...this.model.summaryByEntity.entries()].filter(kv => kv[0] !== this.model?.firstPartyEntity);
76+
if (!entries.length) {
77+
return html`<div class="insight-section">${i18nString(UIStrings.noThirdParties)}</div>`;
78+
}
7279

7380
const topTransferSizeEntries = entries.sort((a, b) => b[1].transferSize - a[1].transferSize).slice(0, 6);
7481
const topMainThreadTimeEntries = entries.sort((a, b) => b[1].mainThreadTime - a[1].mainThreadTime).slice(0, 6);

0 commit comments

Comments
 (0)