| Server IP : 35.80.110.71 / Your IP : 216.73.216.221 Web Server : Apache/2.4.58 (Ubuntu) System : Linux ip-172-31-21-44 6.17.0-1019-aws #19~24.04.1-Ubuntu SMP Tue Jun 23 18:53:06 UTC 2026 x86_64 User : ubuntu ( 1000) PHP Version : 8.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /lib/node_modules/lighthouse/flow-report/src/ |
Upload File : |
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {FunctionComponent} from 'preact';
import {useEffect, useState} from 'preact/hooks';
import {NavigationIcon, SnapshotIcon, TimespanIcon} from './icons';
import {getFilmstripFrames, getScreenDimensions} from './util';
import {Util} from '../../shared/util.js';
const ANIMATION_FRAME_DURATION_MS = 500;
const Separator: FunctionComponent = () => {
return <div className="Separator" role="separator"></div>;
};
const FlowStepIcon: FunctionComponent<{mode: LH.Result.GatherMode}> = ({mode}) => {
return <>
{
mode === 'navigation' && <NavigationIcon/>
}
{
mode === 'timespan' && <TimespanIcon/>
}
{
mode === 'snapshot' && <SnapshotIcon/>
}
</>;
};
const FlowSegment: FunctionComponent<{mode?: LH.Result.GatherMode}> = ({mode}) => {
return (
<div className="FlowSegment">
<div className="FlowSegment__top-line"/>
{
mode && <FlowStepIcon mode={mode}/>
}
<div className="FlowSegment__bottom-line"/>
</div>
);
};
const FlowStepAnimatedThumbnail: FunctionComponent<{
frames: Array<{data: string}>,
width: number,
height: number,
}> = ({frames, width, height}) => {
const [frameIndex, setFrameIndex] = useState(0);
// Handle a frame array of a different length being set.
const effectiveFrameIndex = frameIndex % frames.length;
useEffect(() => {
const interval = setInterval(
() => setFrameIndex(i => (i + 1) % frames.length),
ANIMATION_FRAME_DURATION_MS
);
return () => clearInterval(interval);
}, [frames.length]);
return (
<img
className="FlowStepThumbnail"
data-testid="FlowStepAnimatedThumbnail"
src={frames[effectiveFrameIndex].data}
style={{width, height}}
alt="Animated screenshots of a page tested by Lighthouse"
/>
);
};
const FlowStepThumbnail: FunctionComponent<{
lhr: LH.Result,
width?: number,
height?: number,
}> = ({lhr, width, height}) => {
const frames = getFilmstripFrames(lhr);
// Resize the image to fit the viewport aspect ratio.
const dimensions = getScreenDimensions(lhr);
if (width && height === undefined) {
height = dimensions.height * width / dimensions.width;
} else if (height && width === undefined) {
width = dimensions.width * height / dimensions.height;
}
if (!width || !height) {
// eslint-disable-next-line no-console
console.warn(new Error('FlowStepThumbnail requested without any dimensions').stack);
return <></>;
}
let thumbnail;
if (frames?.length) {
thumbnail = frames[frames.length - 1].data;
if (lhr.gatherMode === 'timespan') {
return <FlowStepAnimatedThumbnail frames={frames} width={width} height={height} />;
}
} else {
thumbnail = Util.getFullPageScreenshot(lhr)?.screenshot.data;
}
return <>
{
thumbnail &&
<img
className="FlowStepThumbnail"
src={thumbnail}
style={{width, height}}
alt="Screenshot of a page tested by Lighthouse"
/>
}
</>;
};
export {
Separator,
FlowStepIcon,
FlowSegment,
FlowStepThumbnail,
};