/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {FunctionComponent} from 'preact';
import {ReportUtils} from '../../../report/renderer/report-utils.js';
import {Separator} from '../common';
import {CategoryScore} from '../wrappers/category-score';
import {useI18n, useStringFormatter, useLocalizedStrings} from '../i18n/i18n';
import {Markdown} from '../wrappers/markdown';
import type {UIStringsType} from '../i18n/ui-strings';
const MAX_TOOLTIP_AUDITS = 2;
type ScoredAuditRef = LH.ReportResult.AuditRef & {result: {score: number}};
function getGatherModeLabel(gatherMode: LH.Result.GatherMode, strings: UIStringsType) {
switch (gatherMode) {
case 'navigation': return strings.navigationReport;
case 'timespan': return strings.timespanReport;
case 'snapshot': return strings.snapshotReport;
}
}
function getCategoryRating(rating: string, strings: UIStringsType) {
switch (rating) {
case 'pass': return strings.ratingPass;
case 'average': return strings.ratingAverage;
case 'fail': return strings.ratingFail;
case 'error': return strings.ratingError;
}
}
function getScoreToBeGained(audit: ScoredAuditRef): number {
return audit.weight * (1 - audit.result.score);
}
const SummaryTooltipAudit: FunctionComponent<{audit: LH.ReportResult.AuditRef}> = ({audit}) => {
const rating = ReportUtils.calculateRating(audit.result.score, audit.result.scoreDisplayMode);
return (
);
};
const SummaryTooltipAudits: FunctionComponent<{category: LH.ReportResult.Category}> =
({category}) => {
const strings = useLocalizedStrings();
function isRelevantAudit(audit: LH.ReportResult.AuditRef): audit is ScoredAuditRef {
return audit.result.score !== null &&
// Metrics should not be displayed in this group.
audit.group !== 'metrics' &&
// Audits in group "hidden" should not be counted.
audit.group !== 'hidden' &&
// We don't want unweighted audits except for performance diagnostics.
(audit.weight > 0 || audit.group === 'diagnostics') &&
// Passing audits should never be high impact.
!ReportUtils.showAsPassed(audit.result);
}
const audits = category.auditRefs
.filter(isRelevantAudit)
.sort((a, b) => {
// Remaining score should always be 0 for perf opportunities because weight is 0.
// In that case, we want to sort by `overallSavingsMs`.
const remainingScoreA = getScoreToBeGained(a);
const remainingScoreB = getScoreToBeGained(b);
if (remainingScoreA !== remainingScoreB) return remainingScoreB - remainingScoreA;
if (a.result.score !== b.result.score) return a.result.score - b.result.score;
// TODO: Sort using overall impact from metric savings, not just LCP
const aLcpSavings = a.result.metricSavings?.LCP || 0;
const bLcpSavings = b.result.metricSavings?.LCP || 0;
return bLcpSavings - aLcpSavings;
})
.splice(0, MAX_TOOLTIP_AUDITS);
if (!audits.length) return null;
return (
{strings.highestImpact}
{
audits.map(audit =>
)
}
);
};
const SummaryTooltip: FunctionComponent<{
category: LH.ReportResult.Category,
gatherMode: LH.Result.GatherMode,
url: string,
}> = ({category, gatherMode, url}) => {
const strings = useLocalizedStrings();
const str_ = useStringFormatter();
const {
numPassed,
numPassableAudits,
numInformative,
totalWeight,
} = ReportUtils.calculateCategoryFraction(category);
const i18n = useI18n();
const displayAsFraction = ReportUtils.shouldDisplayAsFraction(gatherMode);
const score = displayAsFraction ?
numPassed / numPassableAudits :
category.score;
const rating = score === null ? 'error' : ReportUtils.calculateRating(score);
return (
{getGatherModeLabel(gatherMode, strings)}
{url}
{category.title}
{
totalWeight !== 0 &&
{getCategoryRating(rating, strings)}
{
!displayAsFraction && category.score !== null && <>
ยท
{i18n.formatter.formatInteger(category.score * 100)}
>
}
}
{str_(strings.passedAuditCount, {numPassed})}
/
{str_(strings.passableAuditCount, {numPassableAudits})}
{numInformative !== 0 &&
{str_(strings.informativeAuditCount, {numInformative})}
}
);
};
const SummaryCategory: FunctionComponent<{
category: LH.ReportResult.Category|undefined,
href: string,
gatherMode: LH.Result.GatherMode,
finalDisplayedUrl: string,
}> = ({category, href, gatherMode, finalDisplayedUrl}) => {
return (
);
};
export {
SummaryTooltip,
SummaryCategory,
};