Skip to content

Commit

Permalink
Fix/new performance UI (#94678)
Browse files Browse the repository at this point in the history
* adds a new circular progress component for performane score

* adds metric tab bar to a v2 component with performance overall metric

* add performance overall score as a type of metric

* use a v2 prop to show version 2 metic and core web vital components

* add overall performance metric fields

* add circular bar

* fix issue where performance tab was showing on the logged-out version

* show error component when there's an error

* adds a new circular progress component for performane score

* adds metric tab bar to a v2 component with performance overall metric

* add performance overall score as a type of metric

* use a v2 prop to show version 2 metic and core web vital components

* add overall performance metric fields

* add circular bar

* fix issue where performance tab was showing on the logged-out version

* show error component when there's an error

* remove duplicate prop
  • Loading branch information
vykes-mac authored Sep 18, 2024
1 parent c46d75e commit 78adf4a
Show file tree
Hide file tree
Showing 14 changed files with 354 additions and 88 deletions.
1 change: 1 addition & 0 deletions client/data/site-profiler/metrics-dictionaries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function getBasicMetricsFromPerfReport( metrics?: any ): BasicMetricsScor
ttfb: metrics.ttfb,
inp: metrics.inp,
tbt: metrics.tbt,
overall: metrics.overall,
};
return getBasicMetricsScored( basicMetrics );
}
3 changes: 2 additions & 1 deletion client/data/site-profiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export interface HostingProviderQueryResponse {
hosting_provider: HostingProvider;
}

export type Metrics = 'cls' | 'lcp' | 'fcp' | 'ttfb' | 'inp' | 'tbt';
export type Metrics = 'cls' | 'lcp' | 'fcp' | 'ttfb' | 'inp' | 'tbt' | 'overall';

export type Scores = 'good' | 'needs-improvement' | 'poor';

Expand Down Expand Up @@ -145,6 +145,7 @@ export type PerformanceMetricsHistory = {
cls?: number[];
inp?: number[];
tbt?: number[];
overall?: number[];
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const PerformanceReport = ( {
performanceReport={ performanceReport }
url={ url }
hash={ hash }
showV2
displayThumbnail={ false }
displayNewsletterBanner={ false }
displayMigrationBanner={ false }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { CircularProgressBar } from '@automattic/components';
import './style.scss';

type CircularPerformanceScoreProps = {
score: number;
size: number;
steps?: number;
};

export const CircularPerformanceScore = ( {
score,
size,
steps = 100,
}: CircularPerformanceScoreProps ) => {
const getStatus = ( value: number ) => {
if ( value <= 49 ) {
return 'poor';
} else if ( value > 49 && value < 90 ) {
return 'needs-improvement';
}
return 'good';
};

return (
<div className={ `circular-performance-bar ${ getStatus( score ) }` }>
<CircularProgressBar
currentStep={ score }
size={ size }
numberOfSteps={ steps }
showProgressText={ false }
/>
<div className="circular-performance-score">{ score }</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
@import "@automattic/components/src/styles/typography";

.circular-performance-bar {
position: relative;
display: inline-block;

&.good {
color: #00ba37;
.circular__progress-bar .circular__progress-bar-fill-circle {
stroke: #00ba37;
}
}

&.needs-improvement {
color: #d67709;
.circular__progress-bar .circular__progress-bar-fill-circle {
stroke: #d67709;
}
}

&.poor {
color: #d63638;
.circular__progress-bar .circular__progress-bar-fill-circle {
stroke: #d63638;
}
}
}

.circular-performance-score {
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
font-family: $font-sf-pro-display;
font-size: $font-size-header-small;
font-weight: 400;
}

10 changes: 6 additions & 4 deletions client/hosting/performance/site-performance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ const usePerformanceReport = (
) => {
const { url = '', hash = '' } = wpcom_performance_url || {};

const { data: basicMetrics } = useUrlBasicMetricsQuery( url, hash, true );
const { data: basicMetrics, isError } = useUrlBasicMetricsQuery( url, hash, true );
const { final_url: finalUrl, token } = basicMetrics || {};
const { data: performanceInsights, isLoading: isLoadingInsights } =
useUrlPerformanceInsightsQuery( url, token ?? hash );
const { data: performanceInsights, isError: isErrorInsights } = useUrlPerformanceInsightsQuery(
url,
token ?? hash
);

const mobileReport =
typeof performanceInsights?.mobile === 'string' ? undefined : performanceInsights?.mobile;
Expand Down Expand Up @@ -73,7 +75,7 @@ const usePerformanceReport = (
url: finalUrl ?? url,
hash: getHashOrToken( hash, token, activeTab === 'mobile' ? mobileLoaded : desktopLoaded ),
isLoading: activeTab === 'mobile' ? ! mobileLoaded : ! desktopLoaded,
isError: ! isLoadingInsights && ! basicMetrics,
isError: isError || isErrorInsights,
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useTranslate } from 'i18n-calypso';
import { Metrics, PerformanceMetricsHistory } from 'calypso/data/site-profiler/types';
import { CircularPerformanceScore } from 'calypso/hosting/performance/components/circular-performance-score/circular-performance-score';
import {
metricsNames,
metricsTresholds,
Expand Down Expand Up @@ -30,7 +31,7 @@ export const CoreWebVitalsDetailsV2: React.FC< CoreWebVitalsDetailsProps > = ( {
const { name: displayName } = metricsNames[ activeTab ];
const value = metrics[ activeTab ];

const { good, needsImprovement } = metricsTresholds[ activeTab ];
const { good, needsImprovement, bad } = metricsTresholds[ activeTab ];

const formatUnit = ( value: number ) => {
if ( [ 'lcp', 'fcp', 'ttfb' ].includes( activeTab ) ) {
Expand Down Expand Up @@ -85,12 +86,14 @@ export const CoreWebVitalsDetailsV2: React.FC< CoreWebVitalsDetailsProps > = ( {

const status = mapThresholdsToStatus( activeTab as Metrics, value );
const statusClass = status === 'needsImprovement' ? 'needs-improvement' : status;
const isPerformanceScoreSelected = activeTab === 'overall';

return (
<div
className="core-web-vitals-display__details"
style={ {
flexDirection: 'column',
borderRadius: '6px',
} }
>
<div className="core-web-vitals-display__description">
Expand All @@ -106,15 +109,37 @@ export const CoreWebVitalsDetailsV2: React.FC< CoreWebVitalsDetailsProps > = ( {
} }
>
<span className="core-web-vitals-display__description-subheading">{ displayName }</span>

<div className={ `core-web-vitals-display__metric ${ statusClass }` }>
{ displayValue( activeTab as Metrics, value ) }
{ isPerformanceScoreSelected ? (
<div
className="metric-tab-bar__tab-metric"
css={ {
marginTop: '16px',
} }
>
<CircularPerformanceScore score={ value } size={ 76 } />
</div>
) : (
displayValue( activeTab as Metrics, value )
) }
</div>
<p>
{ metricValuations[ activeTab ].explanation }
&nbsp;
<a href={ `https://web.dev/articles/${ activeTab }` }>
{ translate( 'Learn more ↗' ) }
</a>
{ isPerformanceScoreSelected ? (
<a
href="https://developer.chrome.com/docs/lighthouse/performance/performance-scoring"
target="_blank"
rel="noreferrer"
>
{ translate( 'See calculator ↗' ) }
</a>
) : (
<a href={ `https://web.dev/articles/${ activeTab }` }>
{ translate( 'Learn more ↗' ) }
</a>
) }
</p>
</div>
<StatusSection value={ status } recommendationsQuantity={ 3 } />
Expand All @@ -124,39 +149,60 @@ export const CoreWebVitalsDetailsV2: React.FC< CoreWebVitalsDetailsProps > = ( {
<StatusIndicator speed="good" />
<div className="range-heading">{ translate( 'Excellent' ) }</div>
<div className="range-subheading">
{ translate( '(0–%(to)s%(unit)s)', {
args: { to: formatUnit( good ), unit: displayUnit() },
comment: 'Displaying a time range, eg. 0-1s',
} ) }
{ isPerformanceScoreSelected
? translate( '(90–%(to)s)', {
args: { to: formatUnit( good ) },
comment: 'Displaying a percentage range, eg. 90-100',
} )
: translate( '(0–%(to)s%(unit)s)', {
args: { to: formatUnit( good ), unit: displayUnit() },
comment: 'Displaying a time range, eg. 0-1s',
} ) }
</div>
</div>
<div className="range">
<StatusIndicator speed="needsImprovement" />

<div className="range-heading">{ translate( 'Needs Improvement' ) }</div>
<div className="range-subheading">
{ translate( '(%(from)s–%(to)s%(unit)s)', {
args: {
from: formatUnit( good ),
to: formatUnit( needsImprovement ),
unit: displayUnit(),
},
comment: 'Displaying a time range, eg. 2-3s',
} ) }
{ isPerformanceScoreSelected
? translate( '(%(from)s–%(to)s)', {
args: {
from: 50,
to: formatUnit( needsImprovement ),
},
comment: 'Displaying a percentage range, eg. 50-89',
} )
: translate( '(%(from)s–%(to)s%(unit)s)', {
args: {
from: formatUnit( good ),
to: formatUnit( needsImprovement ),
unit: displayUnit(),
},
comment: 'Displaying a time range, eg. 2-3s',
} ) }
</div>
</div>
<div className="range">
<StatusIndicator speed="bad" />

<div className="range-heading">{ translate( 'Poor' ) }</div>
<div className="range-subheading">
{ translate( '(Over %(from)s%(unit)s) ', {
args: {
from: formatUnit( needsImprovement ),
unit: displayUnit(),
},
comment: 'Displaying a time range, eg. >2s',
} ) }
{ isPerformanceScoreSelected
? translate( '(%(from)s-%(to)s) ', {
args: {
from: 0,
to: formatUnit( bad ),
},
comment: 'Displaying a percentage range, eg. 0-49',
} )
: translate( '(Over %(from)s%(unit)s) ', {
args: {
from: formatUnit( needsImprovement ),
unit: displayUnit(),
},
comment: 'Displaying a time range, eg. >2s',
} ) }
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useDesktopBreakpoint } from '@automattic/viewport-react';
import { useState } from 'react';
import clsx from 'clsx';
import { lazy, Suspense, useState } from 'react';
import {
Metrics,
PerformanceMetricsHistory,
Expand All @@ -8,30 +9,55 @@ import {
import { CoreWebVitalsAccordion } from '../core-web-vitals-accordion';
import { MetricTabBar } from '../metric-tab-bar';
import { CoreWebVitalsDetails } from './core-web-vitals-details';

import { CoreWebVitalsDetailsV2 } from './core-web-vitals-details_v2';
import './style.scss';

type CoreWebVitalsDisplayProps = Record< Metrics, number > & {
history: PerformanceMetricsHistory;
audits: Record< string, PerformanceMetricsItemQueryResponse >;
recommendationsRef: React.RefObject< HTMLDivElement > | null;
showV2?: boolean;
};

const MetricTabBarV2 = lazy( () => import( '../metric-tab-bar/metric-tab-bar-v2' ) );

export const CoreWebVitalsDisplay = ( props: CoreWebVitalsDisplayProps ) => {
const defaultTab = 'fcp';
const defaultTab = props.showV2 ? 'overall' : 'fcp';
const [ activeTab, setActiveTab ] = useState< Metrics | null >( defaultTab );
const isDesktop = useDesktopBreakpoint();

const details = props.showV2 ? (
<CoreWebVitalsDetailsV2 activeTab={ activeTab } { ...props } />
) : (
<CoreWebVitalsDetails activeTab={ activeTab } { ...props } />
);

const metricTabBar = props.showV2 ? (
<Suspense fallback={ null }>
<MetricTabBarV2
activeTab={ activeTab ?? defaultTab }
setActiveTab={ setActiveTab }
{ ...props }
/>
</Suspense>
) : (
<MetricTabBar
activeTab={ activeTab ?? defaultTab }
setActiveTab={ setActiveTab }
{ ...props }
/>
);

return (
<>
{ isDesktop && (
<div className="core-web-vitals-display">
<MetricTabBar
activeTab={ activeTab ?? defaultTab }
setActiveTab={ setActiveTab }
{ ...props }
/>
<CoreWebVitalsDetails activeTab={ activeTab } { ...props } />
<div
className={ clsx( 'core-web-vitals-display', {
[ 'core-web-vitals-display-v2' ]: props.showV2,
} ) }
>
{ metricTabBar }
{ details }
</div>
) }
{ ! isDesktop && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ $blueberry-color: #3858e9;
}

//v2
.core-web-vitals-display-v2 {
display: flex;
flex-direction: row;
width: 100%;
gap: 16px;
}

.core-web-vitals-display__metric {
font-family: $font-sf-pro-display;
font-size: $font-size-header;
Expand All @@ -127,7 +134,7 @@ $blueberry-color: #3858e9;
color: #d67709;
}

&.poor {
&.bad {
color: #d63638;
}
}
Expand Down
Loading

0 comments on commit 78adf4a

Please sign in to comment.