lighthouse 8.6.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/report/bundle.esm.js +5994 -0
- package/dist/report/flow.js +30 -13
- package/dist/report/standalone.js +41 -35
- package/flow-report/.eslintrc.cjs +2 -0
- package/flow-report/assets/standalone-flow-template.html +3 -2
- package/flow-report/assets/styles.css +108 -31
- package/flow-report/src/app.tsx +18 -18
- package/flow-report/src/common.tsx +28 -15
- package/flow-report/src/header.tsx +12 -13
- package/flow-report/src/help-dialog.tsx +3 -4
- package/flow-report/src/i18n/i18n.tsx +57 -16
- package/flow-report/src/i18n/ui-strings.js +50 -0
- package/flow-report/src/icons.tsx +36 -8
- package/flow-report/src/sidebar/flow.tsx +3 -3
- package/flow-report/src/sidebar/sidebar.tsx +35 -14
- package/flow-report/src/summary/category.tsx +97 -24
- package/flow-report/src/summary/summary.tsx +21 -14
- package/flow-report/src/topbar.tsx +9 -5
- package/flow-report/src/util.ts +33 -26
- package/flow-report/src/wrappers/category-score.tsx +0 -3
- package/flow-report/src/wrappers/markdown.tsx +27 -0
- package/flow-report/src/wrappers/report-renderer.tsx +10 -3
- package/flow-report/src/wrappers/report.tsx +27 -6
- package/flow-report/standalone-flow.tsx +4 -3
- package/flow-report/test/common-test.tsx +32 -17
- package/flow-report/test/flow-report-pptr-test.ts +46 -0
- package/flow-report/test/header-test.tsx +6 -6
- package/flow-report/test/setup/env-setup.ts +1 -1
- package/flow-report/test/sidebar/sidebar-test.tsx +43 -1
- package/flow-report/test/summary/category-test.tsx +120 -24
- package/flow-report/test/summary/summary-test.tsx +1 -1
- package/flow-report/test/topbar-test.tsx +1 -0
- package/flow-report/test/util-test.tsx +32 -11
- package/flow-report/test/wrappers/category-score-test.tsx +87 -0
- package/flow-report/test/wrappers/markdown-test.tsx +29 -0
- package/flow-report/tsconfig.json +1 -0
- package/jest.config.js +4 -2
- package/lighthouse-cli/.eslintrc.cjs +2 -0
- package/lighthouse-cli/cli-flags.js +1 -1
- package/lighthouse-cli/run.js +1 -1
- package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +0 -0
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +4 -2
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +1 -1
- package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
- package/lighthouse-core/audits/accessibility/axe-audit.js +7 -1
- package/lighthouse-core/audits/audit.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -0
- package/lighthouse-core/audits/byte-efficiency/modern-image-formats.js +4 -2
- package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +11 -10
- package/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js +5 -3
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images-snapshot.js +2 -1
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +2 -1
- package/lighthouse-core/audits/deprecations.js +33 -11
- package/lighthouse-core/audits/dobetterweb/uses-http2.js +27 -11
- package/lighthouse-core/audits/errors-in-console.js +0 -2
- package/lighthouse-core/audits/image-aspect-ratio.js +5 -5
- package/lighthouse-core/audits/image-size-responsive.js +6 -6
- package/lighthouse-core/audits/installable-manifest.js +5 -3
- package/lighthouse-core/audits/preload-lcp-image.js +7 -5
- package/lighthouse-core/audits/script-treemap-data.js +1 -1
- package/lighthouse-core/audits/unsized-images.js +2 -3
- package/lighthouse-core/computed/image-records.js +4 -3
- package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +3 -4
- package/lighthouse-core/computed/metrics/tbt-utils.js +57 -0
- package/lighthouse-core/computed/metrics/total-blocking-time.js +3 -53
- package/lighthouse-core/computed/resource-summary.js +1 -1
- package/lighthouse-core/config/config-helpers.js +21 -10
- package/lighthouse-core/config/constants.js +3 -4
- package/lighthouse-core/config/default-config.js +61 -71
- package/lighthouse-core/fraggle-rock/config/config.js +1 -1
- package/lighthouse-core/fraggle-rock/config/default-config.js +4 -5
- package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +6 -1
- package/lighthouse-core/fraggle-rock/gather/session.js +3 -4
- package/lighthouse-core/gather/connections/cri.js +1 -1
- package/lighthouse-core/gather/driver/storage.js +0 -1
- package/lighthouse-core/gather/driver.js +3 -7
- package/lighthouse-core/gather/fetcher.js +4 -7
- package/lighthouse-core/gather/gather-runner.js +29 -6
- package/lighthouse-core/gather/gatherers/accessibility.js +27 -0
- package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -0
- package/lighthouse-core/gather/gatherers/image-elements.js +0 -3
- package/lighthouse-core/gather/gatherers/inspector-issues.js +5 -0
- package/lighthouse-core/lib/asset-saver.js +7 -4
- package/lighthouse-core/lib/emulation.js +45 -1
- package/lighthouse-core/lib/i18n/i18n.js +19 -8
- package/lighthouse-core/lib/lh-env.js +2 -0
- package/lighthouse-core/lib/proto-preprocessor.js +14 -2
- package/lighthouse-core/lib/tappable-rects.js +8 -15
- package/lighthouse-core/lib/url-shim.js +1 -1
- package/lighthouse-core/runner.js +1 -1
- package/lighthouse-core/util-commonjs.js +65 -46
- package/package.json +27 -17
- package/readme.md +3 -3
- package/report/.eslintrc.cjs +2 -0
- package/report/README.md +1 -1
- package/report/assets/standalone-template.html +2 -3
- package/report/assets/styles.css +360 -254
- package/report/assets/templates.html +21 -76
- package/report/clients/bundle.js +1 -0
- package/report/clients/standalone.js +6 -15
- package/report/generator/README.md +1 -1
- package/report/renderer/api.js +32 -0
- package/report/renderer/category-renderer.js +59 -19
- package/report/renderer/components.js +59 -110
- package/report/renderer/crc-details-renderer.js +15 -12
- package/report/renderer/dom.js +16 -1
- package/report/renderer/drop-down-menu.js +2 -2
- package/report/renderer/element-screenshot-renderer.js +8 -8
- package/report/renderer/features-util.js +1 -1
- package/report/renderer/open-tab.js +9 -3
- package/report/renderer/performance-category-renderer.js +55 -34
- package/report/renderer/pwa-category-renderer.js +0 -10
- package/report/renderer/report-renderer.js +91 -44
- package/report/renderer/report-ui-features.js +36 -33
- package/report/renderer/swap-locale-feature.js +3 -3
- package/report/renderer/topbar-features.js +53 -48
- package/report/renderer/util.js +66 -46
- package/report/test/clients/bundle-test.js +70 -0
- package/report/test/renderer/category-renderer-test.js +48 -3
- package/report/test/renderer/i18n-test.js +0 -7
- package/report/test/renderer/performance-category-renderer-test.js +51 -14
- package/report/test/renderer/pwa-category-renderer-test.js +6 -6
- package/report/test/renderer/report-renderer-axe-test.js +10 -12
- package/report/test/renderer/report-renderer-test.js +23 -22
- package/report/test/renderer/report-ui-features-test.js +20 -10
- package/report/test/renderer/text-encoding-test.js +1 -1
- package/report/test/renderer/util-test.js +35 -31
- package/report/test-assets/faux-psi-template.html +3 -11
- package/report/test-assets/faux-psi.js +26 -22
- package/report/types/html-renderer.d.ts +2 -0
- package/report/types/report-renderer.d.ts +23 -0
- package/shared/localization/format.js +64 -30
- package/shared/localization/locales/ar-XB.json +72 -75
- package/shared/localization/locales/ar.json +72 -75
- package/shared/localization/locales/bg.json +72 -75
- package/shared/localization/locales/ca.json +72 -75
- package/shared/localization/locales/cs.json +89 -92
- package/shared/localization/locales/da.json +72 -75
- package/shared/localization/locales/de.json +89 -92
- package/shared/localization/locales/el.json +72 -75
- package/shared/localization/locales/en-GB.json +72 -75
- package/shared/localization/locales/en-US.json +75 -75
- package/shared/localization/locales/en-XA.json +72 -75
- package/shared/localization/locales/en-XL.json +75 -75
- package/shared/localization/locales/es-419.json +90 -93
- package/shared/localization/locales/es.json +90 -93
- package/shared/localization/locales/fi.json +72 -75
- package/shared/localization/locales/fil.json +72 -75
- package/shared/localization/locales/fr.json +89 -92
- package/shared/localization/locales/he.json +73 -76
- package/shared/localization/locales/hi.json +72 -75
- package/shared/localization/locales/hr.json +72 -75
- package/shared/localization/locales/hu.json +89 -92
- package/shared/localization/locales/id.json +89 -92
- package/shared/localization/locales/it.json +89 -92
- package/shared/localization/locales/ja.json +89 -92
- package/shared/localization/locales/ko.json +89 -92
- package/shared/localization/locales/lt.json +89 -92
- package/shared/localization/locales/lv.json +95 -98
- package/shared/localization/locales/nl.json +89 -92
- package/shared/localization/locales/no.json +72 -75
- package/shared/localization/locales/pl.json +72 -75
- package/shared/localization/locales/pt-PT.json +72 -75
- package/shared/localization/locales/pt.json +89 -92
- package/shared/localization/locales/ro.json +90 -93
- package/shared/localization/locales/ru.json +89 -92
- package/shared/localization/locales/sk.json +89 -92
- package/shared/localization/locales/sl.json +89 -92
- package/shared/localization/locales/sr-Latn.json +89 -92
- package/shared/localization/locales/sr.json +89 -92
- package/shared/localization/locales/sv.json +72 -75
- package/shared/localization/locales/ta.json +89 -92
- package/shared/localization/locales/te.json +89 -92
- package/shared/localization/locales/th.json +89 -92
- package/shared/localization/locales/tr.json +89 -92
- package/shared/localization/locales/uk.json +92 -95
- package/shared/localization/locales/vi.json +89 -92
- package/shared/localization/locales/zh-HK.json +89 -92
- package/shared/localization/locales/zh-TW.json +89 -92
- package/shared/localization/locales/zh.json +89 -92
- package/shared/localization/locales.js +6 -0
- package/shared/test/localization/format-test.js +45 -9
- package/shared/test/localization/swap-locale-test.js +0 -12
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +19 -11
- package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
- package/third-party/download-content-shell/download-content-shell.js +2 -2
- package/third-party/download-content-shell/utils.js +0 -24
- package/tsconfig-all.json +2 -2
- package/tsconfig.json +0 -1
- package/types/artifacts.d.ts +7 -7
- package/types/enquirer.d.ts +3 -1
- package/types/lhr/audit-details.d.ts +6 -5
- package/types/lhr/flow.d.ts +3 -2
- package/types/lhr/lhr.d.ts +1 -1
- package/types/node.d.ts +5 -5
- package/types/rollup-plugin-postprocess.d.ts +10 -0
- package/changelog.md +0 -5490
- package/lighthouse-core/audits/dobetterweb/appcache-manifest.js +0 -67
- package/lighthouse-core/audits/dobetterweb/external-anchors-use-rel-noopener.js +0 -96
- package/lighthouse-core/audits/redirects-http.js +0 -59
- package/lighthouse-core/gather/gatherers/dobetterweb/appcache.js +0 -34
- package/lighthouse-core/gather/gatherers/http-redirect.js +0 -46
- package/lighthouse-core/lib/i18n/locales/en-US.ctc.json +0 -6699
- package/lighthouse-core/lib/i18n/locales/en-XL.ctc.json +0 -6672
- package/lighthouse-core/scripts/package.json +0 -4
- package/report/clients/psi.js +0 -158
- package/report/test/clients/psi-test.js +0 -143
- package/shared/localization/locales/en-US.ctc.json +0 -6877
- package/shared/localization/locales/en-XL.ctc.json +0 -6852
|
@@ -7,32 +7,68 @@
|
|
|
7
7
|
import {createContext, FunctionComponent} from 'preact';
|
|
8
8
|
import {useContext, useMemo} from 'preact/hooks';
|
|
9
9
|
|
|
10
|
+
import {formatMessage} from '../../../shared/localization/format';
|
|
10
11
|
import {I18n} from '../../../report/renderer/i18n';
|
|
11
12
|
import {UIStrings} from './ui-strings';
|
|
12
|
-
import {
|
|
13
|
+
import {useFlowResult} from '../util';
|
|
13
14
|
import strings from './localized-strings';
|
|
15
|
+
import {Util} from '../../../report/renderer/util';
|
|
14
16
|
|
|
15
|
-
const I18nContext = createContext
|
|
17
|
+
const I18nContext = createContext(new I18n('en-US', {...Util.UIStrings, ...UIStrings}));
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
function useLhrLocale() {
|
|
20
|
+
const flowResult = useFlowResult();
|
|
21
|
+
const firstLhr = flowResult.steps[0].lhr;
|
|
22
|
+
const locale = firstLhr.configSettings.locale;
|
|
23
|
+
|
|
24
|
+
if (flowResult.steps.some(step => step.lhr.configSettings.locale !== locale)) {
|
|
25
|
+
console.warn('LHRs have inconsistent locales');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
locale,
|
|
30
|
+
lhrStrings: firstLhr.i18n.rendererFormattedStrings,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function useI18n() {
|
|
35
|
+
return useContext(I18nContext);
|
|
21
36
|
}
|
|
22
37
|
|
|
23
|
-
|
|
38
|
+
function useLocalizedStrings() {
|
|
24
39
|
const i18n = useI18n();
|
|
25
40
|
return i18n.strings;
|
|
26
41
|
}
|
|
27
42
|
|
|
28
|
-
|
|
29
|
-
const locale =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
function useStringFormatter() {
|
|
44
|
+
const {locale} = useLhrLocale();
|
|
45
|
+
return (str: string, values?: Record<string, string|number>) => {
|
|
46
|
+
return formatMessage(str, values, locale);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const I18nProvider: FunctionComponent = ({children}) => {
|
|
51
|
+
const {locale, lhrStrings} = useLhrLocale();
|
|
52
|
+
|
|
53
|
+
const i18n = useMemo(() => {
|
|
54
|
+
const i18n = new I18n(locale, {
|
|
55
|
+
// Set any missing lhr strings to default (english) values.
|
|
56
|
+
...Util.UIStrings,
|
|
57
|
+
// Preload with strings from the first lhr.
|
|
58
|
+
// Used for legacy report components imported into the flow report.
|
|
59
|
+
...lhrStrings,
|
|
60
|
+
// Set any missing flow strings to default (english) values.
|
|
61
|
+
...UIStrings,
|
|
62
|
+
// `strings` is generated in build/build-report.js
|
|
63
|
+
...strings[locale],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Initialize renderer util i18n for strings rendered in wrapped components.
|
|
67
|
+
// TODO: Don't attach global i18n to `Util`.
|
|
68
|
+
Util.i18n = i18n;
|
|
69
|
+
|
|
70
|
+
return i18n;
|
|
71
|
+
}, [locale, lhrStrings]);
|
|
36
72
|
|
|
37
73
|
return (
|
|
38
74
|
<I18nContext.Provider value={i18n}>
|
|
@@ -41,4 +77,9 @@ export const I18nProvider: FunctionComponent = ({children}) => {
|
|
|
41
77
|
);
|
|
42
78
|
};
|
|
43
79
|
|
|
44
|
-
|
|
80
|
+
export {
|
|
81
|
+
useI18n,
|
|
82
|
+
useLocalizedStrings,
|
|
83
|
+
useStringFormatter,
|
|
84
|
+
I18nProvider,
|
|
85
|
+
};
|
|
@@ -57,6 +57,30 @@ export const UIStrings = {
|
|
|
57
57
|
ratingFail: 'Poor',
|
|
58
58
|
/** Rating indicating that a report category rating could not be calculated because of an error. */
|
|
59
59
|
ratingError: 'Error',
|
|
60
|
+
/**
|
|
61
|
+
* @description Label indicating the number of Lighthouse reports that evaluate a web page as it loads.
|
|
62
|
+
* @example {2} numNavigation
|
|
63
|
+
*/
|
|
64
|
+
navigationReportCount: `{numNavigation, plural,
|
|
65
|
+
=1 {{numNavigation} navigation report}
|
|
66
|
+
other {{numNavigation} navigation reports}
|
|
67
|
+
}`,
|
|
68
|
+
/**
|
|
69
|
+
* @description Label indicating the number of Lighthouse reports that evaluate a web page over a period of time.
|
|
70
|
+
* @example {2} numTimespan
|
|
71
|
+
*/
|
|
72
|
+
timespanReportCount: `{numTimespan, plural,
|
|
73
|
+
=1 {{numTimespan} timespan report}
|
|
74
|
+
other {{numTimespan} timespan reports}
|
|
75
|
+
}`,
|
|
76
|
+
/**
|
|
77
|
+
* @description Label indicating the number of Lighthouse reports that evaluate a web page at a single point in time.
|
|
78
|
+
* @example {2} numSnapshot
|
|
79
|
+
*/
|
|
80
|
+
snapshotReportCount: `{numSnapshot, plural,
|
|
81
|
+
=1 {{numSnapshot} snapshot report}
|
|
82
|
+
other {{numSnapshot} snapshot reports}
|
|
83
|
+
}`,
|
|
60
84
|
/** Label for a button that saves a Lighthouse report to disk. */
|
|
61
85
|
save: 'Save',
|
|
62
86
|
/** Label for a button that toggles the help modal with explanations on how to interpret the Lighthouse flow report. */
|
|
@@ -83,4 +107,30 @@ export const UIStrings = {
|
|
|
83
107
|
helpUseCaseSnapshot1: 'Find accessibility issues in single page applications or complex forms.',
|
|
84
108
|
/** Example use case for how Lighthouse can be applied in practice. Appears in a list with other examples. */
|
|
85
109
|
helpUseCaseSnapshot2: 'Evaluate best practices of menus and UI elements hidden behind interaction.',
|
|
110
|
+
/**
|
|
111
|
+
* @description Label indicating the number of Lighthouse audits that passed.
|
|
112
|
+
* @example {2} numPassed
|
|
113
|
+
*/
|
|
114
|
+
passedAuditCount: `{numPassed, plural,
|
|
115
|
+
=1 {{numPassed} audit passed}
|
|
116
|
+
other {{numPassed} audits passed}
|
|
117
|
+
}`,
|
|
118
|
+
/**
|
|
119
|
+
* @description Label indicating the number of Lighthouse audits that are possible to pass for a page.
|
|
120
|
+
* @example {2} numPassableAudits
|
|
121
|
+
*/
|
|
122
|
+
passableAuditCount: `{numPassableAudits, plural,
|
|
123
|
+
=1 {{numPassableAudits} passable audit}
|
|
124
|
+
other {{numPassableAudits} passable audits}
|
|
125
|
+
}`,
|
|
126
|
+
/**
|
|
127
|
+
* @description Label indicating the number of Lighthouse audits that are informative.
|
|
128
|
+
* @example {2} numInformative
|
|
129
|
+
*/
|
|
130
|
+
informativeAuditCount: `{numInformative, plural,
|
|
131
|
+
=1 {{numInformative} informative audit}
|
|
132
|
+
other {{numInformative} informative audits}
|
|
133
|
+
}`,
|
|
134
|
+
/** Label for a list of Lighthouse audits that are the most impactful. */
|
|
135
|
+
highestImpact: 'Highest impact',
|
|
86
136
|
};
|
|
@@ -8,7 +8,7 @@ import {FunctionComponent} from 'preact';
|
|
|
8
8
|
|
|
9
9
|
/* eslint-disable max-len */
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const SummaryIcon: FunctionComponent = () => {
|
|
12
12
|
return (
|
|
13
13
|
<svg width="14" viewBox="0 0 18 16" fill="none" role="img">
|
|
14
14
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 2C0 1.17 0.67 0.5 1.5 0.5C2.33 0.5 3 1.17 3 2C3 2.83 2.33 3.5 1.5 3.5C0.67 3.5 0 2.83 0 2ZM0 8C0 7.17 0.67 6.5 1.5 6.5C2.33 6.5 3 7.17 3 8C3 8.83 2.33 9.5 1.5 9.5C0.67 9.5 0 8.83 0 8ZM1.5 12.5C0.67 12.5 0 13.18 0 14C0 14.82 0.68 15.5 1.5 15.5C2.32 15.5 3 14.82 3 14C3 13.18 2.33 12.5 1.5 12.5ZM18 15H5V13H18V15ZM5 9H18V7H5V9ZM5 3V1H18V3H5Z" fill="currentColor"/>
|
|
@@ -16,7 +16,7 @@ export const SummaryIcon: FunctionComponent = () => {
|
|
|
16
16
|
);
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
const NavigationIcon: FunctionComponent = () => {
|
|
20
20
|
return (
|
|
21
21
|
<svg
|
|
22
22
|
width="16"
|
|
@@ -36,7 +36,7 @@ export const NavigationIcon: FunctionComponent = () => {
|
|
|
36
36
|
);
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const TimespanIcon: FunctionComponent = () => {
|
|
40
40
|
return (
|
|
41
41
|
<svg
|
|
42
42
|
width="16"
|
|
@@ -60,7 +60,7 @@ export const TimespanIcon: FunctionComponent = () => {
|
|
|
60
60
|
);
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
const SnapshotIcon: FunctionComponent = () => {
|
|
64
64
|
return (
|
|
65
65
|
<svg
|
|
66
66
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -79,7 +79,7 @@ export const SnapshotIcon: FunctionComponent = () => {
|
|
|
79
79
|
);
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
const CloseIcon: FunctionComponent = () => {
|
|
83
83
|
return (
|
|
84
84
|
<svg
|
|
85
85
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -96,7 +96,7 @@ export const CloseIcon: FunctionComponent = () => {
|
|
|
96
96
|
);
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
const EnvIcon: FunctionComponent = () => {
|
|
100
100
|
return (
|
|
101
101
|
<svg width="15" height="12" viewBox="0 0 15 12" fill="none" role="img">
|
|
102
102
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.33317 2.00008H13.9998V0.666748H3.33317C2.59984 0.666748 1.99984 1.26675 1.99984 2.00008V9.33341H0.666504V11.3334H7.99984V9.33341H3.33317V2.00008ZM13.9998 3.33341H9.99984C9.63317 3.33341 9.33317 3.63341 9.33317 4.00008V10.6667C9.33317 11.0334 9.63317 11.3334 9.99984 11.3334H13.9998C14.3665 11.3334 14.6665 11.0334 14.6665 10.6667V4.00008C14.6665 3.63341 14.3665 3.33341 13.9998 3.33341ZM10.6665 9.33341H13.3332V4.66675H10.6665V9.33341Z" fill="currentColor"/>
|
|
@@ -104,7 +104,15 @@ export const EnvIcon: FunctionComponent = () => {
|
|
|
104
104
|
);
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
const NetworkIcon: FunctionComponent = () => {
|
|
108
|
+
return (
|
|
109
|
+
<svg width="16" height="11" viewBox="0 0 16 11" fill="none" role="img">
|
|
110
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.666687 3.26663L2.00002 4.59997C3.92002 2.67997 6.52669 1.87997 9.02002 2.18663L9.81335 0.399966C6.59335 -0.173367 3.16002 0.779966 0.666687 3.26663ZM10.6 0.599966C10.4867 0.599966 10.3867 0.659966 10.3267 0.753299L10.28 0.853299L6.82669 8.61996C6.72002 8.8133 6.65335 9.02663 6.65335 9.25996C6.65335 9.99996 7.25335 10.6 7.99335 10.6C8.63335 10.6 9.17335 10.1466 9.30002 9.53996L9.30669 9.51997L10.9334 0.933299C10.9334 0.746633 10.7867 0.599966 10.6 0.599966ZM15.3334 3.26663L14 4.59997C13.1867 3.78663 12.2534 3.17997 11.2534 2.76663L11.6067 0.886633C12.9667 1.38663 14.24 2.1733 15.3334 3.26663ZM11.3334 7.26663L12.6667 5.9333C12.1334 5.39997 11.5334 4.98663 10.8934 4.6733L10.5267 6.61997C10.8067 6.79997 11.08 7.0133 11.3334 7.26663ZM4.66669 7.26663L3.33335 5.9333C4.67335 4.5933 6.45335 3.95997 8.20669 4.0133L7.35335 5.9333C6.37335 6.0733 5.42002 6.5133 4.66669 7.26663Z" fill="currentColor"/>
|
|
111
|
+
</svg>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const CpuIcon: FunctionComponent = () => {
|
|
108
116
|
return (
|
|
109
117
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" role="img">
|
|
110
118
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5 7.16667V5.5H13.8333V3.83333C13.8333 2.91667 13.0833 2.16667 12.1667 2.16667H10.5V0.5H8.83333V2.16667H7.16667V0.5H5.5V2.16667H3.83333C2.91667 2.16667 2.16667 2.91667 2.16667 3.83333V5.5H0.5V7.16667H2.16667V8.83333H0.5V10.5H2.16667V12.1667C2.16667 13.0833 2.91667 13.8333 3.83333 13.8333H5.5V15.5H7.16667V13.8333H8.83333V15.5H10.5V13.8333H12.1667C13.0833 13.8333 13.8333 13.0833 13.8333 12.1667V10.5H15.5V8.83333H13.8333V7.16667H15.5ZM10.5 5.5H5.5V10.5H10.5V5.5ZM3.83333 12.1667H12.1667V3.83333H3.83333V12.1667Z" fill="currentColor"/>
|
|
@@ -112,7 +120,7 @@ export const CpuIcon: FunctionComponent = () => {
|
|
|
112
120
|
);
|
|
113
121
|
};
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
const HamburgerIcon: FunctionComponent = () => {
|
|
116
124
|
return (
|
|
117
125
|
<svg viewBox="0 0 18 12" width="18" height="12" role="img">
|
|
118
126
|
<rect width="18" height="2" fill="currentColor"></rect>
|
|
@@ -122,3 +130,23 @@ export const HamburgerIcon: FunctionComponent = () => {
|
|
|
122
130
|
);
|
|
123
131
|
};
|
|
124
132
|
|
|
133
|
+
const InfoIcon: FunctionComponent = () => {
|
|
134
|
+
return (
|
|
135
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
|
136
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 7C13 10.3137 10.3137 13 7 13C3.68629 13 1 10.3137 1 7C1 3.68629 3.68629 1 7 1C10.3137 1 13 3.68629 13 7ZM14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM7.66658 11H6.33325V9.66667H7.66658V11ZM4.33325 5.66667C4.33325 4.19333 5.52659 3 6.99992 3C8.47325 3 9.66658 4.19333 9.66658 5.66667C9.66658 6.52194 9.1399 6.98221 8.62709 7.43036C8.1406 7.85551 7.66658 8.26975 7.66658 9H6.33325C6.33325 7.78582 6.96133 7.30439 7.51355 6.88112C7.94674 6.54907 8.33325 6.25281 8.33325 5.66667C8.33325 4.93333 7.73325 4.33333 6.99992 4.33333C6.26658 4.33333 5.66658 4.93333 5.66658 5.66667H4.33325Z" fill="currentColor"/>
|
|
137
|
+
</svg>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
SummaryIcon,
|
|
143
|
+
NavigationIcon,
|
|
144
|
+
TimespanIcon,
|
|
145
|
+
SnapshotIcon,
|
|
146
|
+
CloseIcon,
|
|
147
|
+
EnvIcon,
|
|
148
|
+
NetworkIcon,
|
|
149
|
+
CpuIcon,
|
|
150
|
+
HamburgerIcon,
|
|
151
|
+
InfoIcon,
|
|
152
|
+
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import {FunctionComponent} from 'preact';
|
|
8
8
|
|
|
9
9
|
import {FlowSegment} from '../common';
|
|
10
|
-
import {classNames,
|
|
10
|
+
import {classNames, useHashState, useFlowResult} from '../util';
|
|
11
11
|
import {Separator} from '../common';
|
|
12
12
|
|
|
13
13
|
const SidebarFlowStep: FunctionComponent<{
|
|
@@ -41,7 +41,7 @@ const SidebarFlowSeparator: FunctionComponent = () => {
|
|
|
41
41
|
|
|
42
42
|
export const SidebarFlow: FunctionComponent = () => {
|
|
43
43
|
const flowResult = useFlowResult();
|
|
44
|
-
const
|
|
44
|
+
const hashState = useHashState();
|
|
45
45
|
|
|
46
46
|
return (
|
|
47
47
|
<div className="SidebarFlow">
|
|
@@ -61,7 +61,7 @@ export const SidebarFlow: FunctionComponent = () => {
|
|
|
61
61
|
mode={lhr.gatherMode}
|
|
62
62
|
href={url.href}
|
|
63
63
|
label={name}
|
|
64
|
-
isCurrent={index === (
|
|
64
|
+
isCurrent={index === (hashState && hashState.index)}
|
|
65
65
|
/>
|
|
66
66
|
</>;
|
|
67
67
|
})
|
|
@@ -6,22 +6,23 @@
|
|
|
6
6
|
|
|
7
7
|
import {FunctionComponent} from 'preact';
|
|
8
8
|
|
|
9
|
+
import {Util} from '../../../report/renderer/util';
|
|
9
10
|
import {Separator} from '../common';
|
|
10
|
-
import {useI18n,
|
|
11
|
-
import {CpuIcon, EnvIcon, SummaryIcon} from '../icons';
|
|
12
|
-
import {classNames,
|
|
11
|
+
import {useI18n, useLocalizedStrings} from '../i18n/i18n';
|
|
12
|
+
import {CpuIcon, EnvIcon, NetworkIcon, SummaryIcon} from '../icons';
|
|
13
|
+
import {classNames, useHashState, useFlowResult} from '../util';
|
|
13
14
|
import {SidebarFlow} from './flow';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const strings =
|
|
16
|
+
const SidebarSummary: FunctionComponent = () => {
|
|
17
|
+
const hashState = useHashState();
|
|
18
|
+
const strings = useLocalizedStrings();
|
|
18
19
|
|
|
19
20
|
const url = new URL(location.href);
|
|
20
21
|
url.hash = '#';
|
|
21
22
|
return (
|
|
22
23
|
<a
|
|
23
24
|
href={url.href}
|
|
24
|
-
className={classNames('SidebarSummary', {'Sidebar--current':
|
|
25
|
+
className={classNames('SidebarSummary', {'Sidebar--current': hashState === null})}
|
|
25
26
|
data-testid="SidebarSummary"
|
|
26
27
|
>
|
|
27
28
|
<div className="SidebarSummary__icon">
|
|
@@ -32,20 +33,33 @@ export const SidebarSummary: FunctionComponent = () => {
|
|
|
32
33
|
);
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
36
|
-
|
|
36
|
+
const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
37
|
+
({settings}) => {
|
|
38
|
+
const strings = useLocalizedStrings();
|
|
39
|
+
const env = Util.getEmulationDescriptions(settings);
|
|
37
40
|
|
|
38
41
|
return (
|
|
39
42
|
<div className="SidebarRuntimeSettings">
|
|
40
|
-
<div className="SidebarRuntimeSettings__item">
|
|
43
|
+
<div className="SidebarRuntimeSettings__item" title={strings.runtimeSettingsDevice}>
|
|
41
44
|
<div className="SidebarRuntimeSettings__item--icon">
|
|
42
45
|
<EnvIcon/>
|
|
43
46
|
</div>
|
|
44
47
|
{
|
|
45
|
-
|
|
48
|
+
env.deviceEmulation
|
|
46
49
|
}
|
|
47
50
|
</div>
|
|
48
|
-
<div
|
|
51
|
+
<div
|
|
52
|
+
className="SidebarRuntimeSettings__item"
|
|
53
|
+
title={strings.runtimeSettingsNetworkThrottling}
|
|
54
|
+
>
|
|
55
|
+
<div className="SidebarRuntimeSettings__item--icon">
|
|
56
|
+
<NetworkIcon/>
|
|
57
|
+
</div>
|
|
58
|
+
{
|
|
59
|
+
env.summary
|
|
60
|
+
}
|
|
61
|
+
</div>
|
|
62
|
+
<div className="SidebarRuntimeSettings__item" title={strings.runtimeSettingsCPUThrottling}>
|
|
49
63
|
<div className="SidebarRuntimeSettings__item--icon">
|
|
50
64
|
<CpuIcon/>
|
|
51
65
|
</div>
|
|
@@ -57,7 +71,7 @@ const SidebarRuntimeSettings: FunctionComponent<{settings: LH.ConfigSettings}> =
|
|
|
57
71
|
);
|
|
58
72
|
};
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
const SidebarHeader: FunctionComponent<{title: string, date: string}> = ({title, date}) => {
|
|
61
75
|
const i18n = useI18n();
|
|
62
76
|
return (
|
|
63
77
|
<div className="SidebarHeader">
|
|
@@ -67,7 +81,7 @@ export const SidebarHeader: FunctionComponent<{title: string, date: string}> = (
|
|
|
67
81
|
);
|
|
68
82
|
};
|
|
69
83
|
|
|
70
|
-
|
|
84
|
+
const Sidebar: FunctionComponent = () => {
|
|
71
85
|
const flowResult = useFlowResult();
|
|
72
86
|
const firstLhr = flowResult.steps[0].lhr;
|
|
73
87
|
return (
|
|
@@ -82,3 +96,10 @@ export const Sidebar: FunctionComponent = () => {
|
|
|
82
96
|
</div>
|
|
83
97
|
);
|
|
84
98
|
};
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
SidebarSummary,
|
|
102
|
+
SidebarRuntimeSettings,
|
|
103
|
+
SidebarHeader,
|
|
104
|
+
Sidebar,
|
|
105
|
+
};
|
|
@@ -9,10 +9,15 @@ import {FunctionComponent} from 'preact';
|
|
|
9
9
|
import {Util} from '../../../report/renderer/util';
|
|
10
10
|
import {Separator} from '../common';
|
|
11
11
|
import {CategoryScore} from '../wrappers/category-score';
|
|
12
|
-
import {
|
|
12
|
+
import {useI18n, useStringFormatter, useLocalizedStrings} from '../i18n/i18n';
|
|
13
|
+
import {Markdown} from '../wrappers/markdown';
|
|
13
14
|
|
|
14
15
|
import type {UIStringsType} from '../i18n/ui-strings';
|
|
15
16
|
|
|
17
|
+
const MAX_TOOLTIP_AUDITS = 2;
|
|
18
|
+
|
|
19
|
+
type ScoredAuditRef = LH.ReportResult.AuditRef & {result: {score: number}};
|
|
20
|
+
|
|
16
21
|
function getGatherModeLabel(gatherMode: LH.Result.GatherMode, strings: UIStringsType) {
|
|
17
22
|
switch (gatherMode) {
|
|
18
23
|
case 'navigation': return strings.navigationReport;
|
|
@@ -30,11 +35,73 @@ function getCategoryRating(rating: string, strings: UIStringsType) {
|
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
function getScoreToBeGained(audit: ScoredAuditRef): number {
|
|
39
|
+
return audit.weight * (1 - audit.result.score);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getOverallSavings(audit: LH.ReportResult.AuditRef): number {
|
|
43
|
+
return (
|
|
44
|
+
audit.result.details &&
|
|
45
|
+
audit.result.details.type === 'opportunity' &&
|
|
46
|
+
audit.result.details.overallSavingsMs
|
|
47
|
+
) || 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const SummaryTooltipAudit: FunctionComponent<{audit: LH.ReportResult.AuditRef}> = ({audit}) => {
|
|
51
|
+
const rating = Util.calculateRating(audit.result.score, audit.result.scoreDisplayMode);
|
|
52
|
+
return (
|
|
53
|
+
<div className={`SummaryTooltipAudit SummaryTooltipAudit--${rating}`}>
|
|
54
|
+
<Markdown text={audit.result.title}/>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const SummaryTooltipAudits: FunctionComponent<{category: LH.ReportResult.Category}> =
|
|
60
|
+
({category}) => {
|
|
61
|
+
const strings = useLocalizedStrings();
|
|
62
|
+
|
|
63
|
+
function isRelevantAudit(audit: LH.ReportResult.AuditRef): audit is ScoredAuditRef {
|
|
64
|
+
return audit.result.score !== null &&
|
|
65
|
+
// Metrics should not be displayed in this group.
|
|
66
|
+
audit.group !== 'metrics' &&
|
|
67
|
+
// Audits in performance group "hidden" should not be counted.
|
|
68
|
+
(audit.group !== 'hidden' || category.id !== 'performance') &&
|
|
69
|
+
// We don't want unweighted audits except for opportunities with potential savings.
|
|
70
|
+
(audit.weight > 0 || getOverallSavings(audit) > 0) &&
|
|
71
|
+
// Passing audits should never be high impact.
|
|
72
|
+
!Util.showAsPassed(audit.result);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const audits = category.auditRefs
|
|
76
|
+
.filter(isRelevantAudit)
|
|
77
|
+
.sort((a, b) => {
|
|
78
|
+
// Remaining score should always be 0 for perf opportunities because weight is 0.
|
|
79
|
+
// In that case, we want to sort by `overallSavingsMs`.
|
|
80
|
+
const remainingScoreA = getScoreToBeGained(a);
|
|
81
|
+
const remainingScoreB = getScoreToBeGained(b);
|
|
82
|
+
if (remainingScoreA !== remainingScoreB) return remainingScoreB - remainingScoreA;
|
|
83
|
+
return getOverallSavings(b) - getOverallSavings(a);
|
|
84
|
+
})
|
|
85
|
+
.splice(0, MAX_TOOLTIP_AUDITS);
|
|
86
|
+
if (!audits.length) return null;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className="SummaryTooltipAudits">
|
|
90
|
+
<div className="SummaryTooltipAudits__title">{strings.highestImpact}</div>
|
|
91
|
+
{
|
|
92
|
+
audits.map(audit => <SummaryTooltipAudit key={audit.id} audit={audit}/>)
|
|
93
|
+
}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const SummaryTooltip: FunctionComponent<{
|
|
34
99
|
category: LH.ReportResult.Category,
|
|
35
|
-
gatherMode: LH.Result.GatherMode
|
|
36
|
-
|
|
37
|
-
|
|
100
|
+
gatherMode: LH.Result.GatherMode,
|
|
101
|
+
url: string,
|
|
102
|
+
}> = ({category, gatherMode, url}) => {
|
|
103
|
+
const strings = useLocalizedStrings();
|
|
104
|
+
const str_ = useStringFormatter();
|
|
38
105
|
const {
|
|
39
106
|
numPassed,
|
|
40
107
|
numPassableAudits,
|
|
@@ -42,14 +109,17 @@ export const SummaryTooltip: FunctionComponent<{
|
|
|
42
109
|
totalWeight,
|
|
43
110
|
} = Util.calculateCategoryFraction(category);
|
|
44
111
|
|
|
112
|
+
const i18n = useI18n();
|
|
45
113
|
const displayAsFraction = Util.shouldDisplayAsFraction(gatherMode);
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
114
|
+
const score = displayAsFraction ?
|
|
115
|
+
numPassed / numPassableAudits :
|
|
116
|
+
category.score;
|
|
117
|
+
const rating = score === null ? 'error' : Util.calculateRating(score);
|
|
49
118
|
|
|
50
119
|
return (
|
|
51
120
|
<div className="SummaryTooltip">
|
|
52
121
|
<div className="SummaryTooltip__title">{getGatherModeLabel(gatherMode, strings)}</div>
|
|
122
|
+
<div className="SummaryTooltip__url">{url}</div>
|
|
53
123
|
<Separator/>
|
|
54
124
|
<div className="SummaryTooltip__category">
|
|
55
125
|
<div className="SummaryTooltip__category-title">
|
|
@@ -60,37 +130,35 @@ export const SummaryTooltip: FunctionComponent<{
|
|
|
60
130
|
<div className={`SummaryTooltip__rating SummaryTooltip__rating--${rating}`}>
|
|
61
131
|
<span>{getCategoryRating(rating, strings)}</span>
|
|
62
132
|
{
|
|
63
|
-
!displayAsFraction && category.score && <>
|
|
133
|
+
!displayAsFraction && category.score !== null && <>
|
|
64
134
|
<span> · </span>
|
|
65
|
-
<span>{category.score * 100}</span>
|
|
135
|
+
<span>{i18n.formatNumber(category.score * 100)}</span>
|
|
66
136
|
</>
|
|
67
137
|
}
|
|
68
138
|
</div>
|
|
69
139
|
}
|
|
70
140
|
</div>
|
|
71
141
|
<div className="SummaryTooltip__fraction">
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
142
|
+
<span>{str_(strings.passedAuditCount, {numPassed})}</span>
|
|
143
|
+
<span> / </span>
|
|
144
|
+
<span>{str_(strings.passableAuditCount, {numPassableAudits})}</span>
|
|
76
145
|
</div>
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
{`${numInformative} informative audits`}
|
|
82
|
-
</div> :
|
|
83
|
-
null
|
|
146
|
+
{numInformative !== 0 &&
|
|
147
|
+
<div className="SummaryTooltip__informative">
|
|
148
|
+
{str_(strings.informativeAuditCount, {numInformative})}
|
|
149
|
+
</div>
|
|
84
150
|
}
|
|
151
|
+
<SummaryTooltipAudits category={category}/>
|
|
85
152
|
</div>
|
|
86
153
|
);
|
|
87
154
|
};
|
|
88
155
|
|
|
89
|
-
|
|
156
|
+
const SummaryCategory: FunctionComponent<{
|
|
90
157
|
category: LH.ReportResult.Category|undefined,
|
|
91
158
|
href: string,
|
|
92
159
|
gatherMode: LH.Result.GatherMode,
|
|
93
|
-
|
|
160
|
+
finalUrl: string,
|
|
161
|
+
}> = ({category, href, gatherMode, finalUrl}) => {
|
|
94
162
|
return (
|
|
95
163
|
<div className="SummaryCategory">
|
|
96
164
|
{
|
|
@@ -101,10 +169,15 @@ export const SummaryCategory: FunctionComponent<{
|
|
|
101
169
|
href={href}
|
|
102
170
|
gatherMode={gatherMode}
|
|
103
171
|
/>
|
|
104
|
-
<SummaryTooltip category={category} gatherMode={gatherMode}/>
|
|
172
|
+
<SummaryTooltip category={category} gatherMode={gatherMode} url={finalUrl}/>
|
|
105
173
|
</div> :
|
|
106
174
|
<div className="SummaryCategory__null" data-testid="SummaryCategory__null"/>
|
|
107
175
|
}
|
|
108
176
|
</div>
|
|
109
177
|
);
|
|
110
178
|
};
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
SummaryTooltip,
|
|
182
|
+
SummaryCategory,
|
|
183
|
+
};
|
|
@@ -11,13 +11,13 @@ import {FlowSegment, FlowStepThumbnail, Separator} from '../common';
|
|
|
11
11
|
import {getModeDescription, useFlowResult} from '../util';
|
|
12
12
|
import {Util} from '../../../report/renderer/util';
|
|
13
13
|
import {SummaryCategory} from './category';
|
|
14
|
-
import {
|
|
14
|
+
import {useStringFormatter, useLocalizedStrings} from '../i18n/i18n';
|
|
15
15
|
|
|
16
16
|
const DISPLAYED_CATEGORIES = ['performance', 'accessibility', 'best-practices', 'seo'];
|
|
17
|
-
const THUMBNAIL_WIDTH =
|
|
17
|
+
const THUMBNAIL_WIDTH = 40;
|
|
18
18
|
|
|
19
19
|
const SummaryNavigationHeader: FunctionComponent<{lhr: LH.Result}> = ({lhr}) => {
|
|
20
|
-
const strings =
|
|
20
|
+
const strings = useLocalizedStrings();
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
23
|
<div className="SummaryNavigationHeader" data-testid="SummaryNavigationHeader">
|
|
@@ -44,13 +44,13 @@ const SummaryNavigationHeader: FunctionComponent<{lhr: LH.Result}> = ({lhr}) =>
|
|
|
44
44
|
/**
|
|
45
45
|
* The div should behave like a JSX <>...</>. This still allows us to identify "rows" with CSS selectors.
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
const SummaryFlowStep: FunctionComponent<{
|
|
48
48
|
lhr: LH.Result,
|
|
49
49
|
label: string,
|
|
50
50
|
hashIndex: number,
|
|
51
51
|
}> = ({lhr, label, hashIndex}) => {
|
|
52
52
|
const reportResult = useMemo(() => Util.prepareReportResult(lhr), [lhr]);
|
|
53
|
-
const strings =
|
|
53
|
+
const strings = useLocalizedStrings();
|
|
54
54
|
const modeDescription = getModeDescription(lhr.gatherMode, strings);
|
|
55
55
|
|
|
56
56
|
return (
|
|
@@ -63,7 +63,7 @@ export const SummaryFlowStep: FunctionComponent<{
|
|
|
63
63
|
<Separator/>
|
|
64
64
|
</div>
|
|
65
65
|
}
|
|
66
|
-
<FlowStepThumbnail
|
|
66
|
+
<FlowStepThumbnail lhr={lhr} width={THUMBNAIL_WIDTH}/>
|
|
67
67
|
<FlowSegment mode={lhr.gatherMode}/>
|
|
68
68
|
<div className="SummaryFlowStep__label">
|
|
69
69
|
<div className="SummaryFlowStep__mode">{modeDescription}</div>
|
|
@@ -76,6 +76,7 @@ export const SummaryFlowStep: FunctionComponent<{
|
|
|
76
76
|
category={reportResult.categories[c]}
|
|
77
77
|
href={`#index=${hashIndex}&anchor=${c}`}
|
|
78
78
|
gatherMode={lhr.gatherMode}
|
|
79
|
+
finalUrl={lhr.finalUrl}
|
|
79
80
|
/>
|
|
80
81
|
))
|
|
81
82
|
}
|
|
@@ -105,9 +106,10 @@ const SummaryFlow: FunctionComponent = () => {
|
|
|
105
106
|
);
|
|
106
107
|
};
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
const SummaryHeader: FunctionComponent = () => {
|
|
109
110
|
const flowResult = useFlowResult();
|
|
110
|
-
const strings =
|
|
111
|
+
const strings = useLocalizedStrings();
|
|
112
|
+
const str_ = useStringFormatter();
|
|
111
113
|
|
|
112
114
|
let numNavigation = 0;
|
|
113
115
|
let numTimespan = 0;
|
|
@@ -126,11 +128,10 @@ export const SummaryHeader: FunctionComponent = () => {
|
|
|
126
128
|
}
|
|
127
129
|
}
|
|
128
130
|
|
|
129
|
-
// TODO(FLOW-I18N): Placeholder format.
|
|
130
131
|
const subtitleCounts = [];
|
|
131
|
-
if (numNavigation) subtitleCounts.push(
|
|
132
|
-
if (numTimespan) subtitleCounts.push(
|
|
133
|
-
if (numSnapshot) subtitleCounts.push(
|
|
132
|
+
if (numNavigation) subtitleCounts.push(str_(strings.navigationReportCount, {numNavigation}));
|
|
133
|
+
if (numTimespan) subtitleCounts.push(str_(strings.timespanReportCount, {numTimespan}));
|
|
134
|
+
if (numSnapshot) subtitleCounts.push(str_(strings.snapshotReportCount, {numSnapshot}));
|
|
134
135
|
const subtitle = subtitleCounts.join(' · ');
|
|
135
136
|
|
|
136
137
|
return (
|
|
@@ -150,8 +151,8 @@ const SummarySectionHeader: FunctionComponent = ({children}) => {
|
|
|
150
151
|
);
|
|
151
152
|
};
|
|
152
153
|
|
|
153
|
-
|
|
154
|
-
const strings =
|
|
154
|
+
const Summary: FunctionComponent = () => {
|
|
155
|
+
const strings = useLocalizedStrings();
|
|
155
156
|
|
|
156
157
|
return (
|
|
157
158
|
<div className="Summary" data-testid="Summary">
|
|
@@ -162,3 +163,9 @@ export const Summary: FunctionComponent = () => {
|
|
|
162
163
|
</div>
|
|
163
164
|
);
|
|
164
165
|
};
|
|
166
|
+
|
|
167
|
+
export {
|
|
168
|
+
SummaryFlowStep,
|
|
169
|
+
SummaryHeader,
|
|
170
|
+
Summary,
|
|
171
|
+
};
|