From 5903f2fcf5ec2522b1705c19b95ba389729eb135 Mon Sep 17 00:00:00 2001 From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com> Date: Tue, 27 May 2025 18:12:20 +0100 Subject: [PATCH 01/10] Refactor LCP component: Introduce error handling and tooltip for optimization failures * Migrate LCP status display logic to a new Status component. * Add ErrorTooltip component to show detailed error messages for failed optimizations. * Update LCP state management to include error handling in the backend. * Introduce new SCSS styles for error tooltips and status display. * Ensure compatibility with existing LCP state management and API responses. --- .../app/assets/src/js/features/lcp/lcp.tsx | 64 +------- .../lcp/lib/stores/lcp-state-types.ts | 7 +- .../lcp/status/error-tooltip.module.scss | 52 +++++++ .../js/features/lcp/status/error-tooltip.tsx | 30 ++++ .../status.module.scss} | 24 +-- .../src/js/features/lcp/status/status.tsx | 145 ++++++++++++++++++ .../optimizations/lcp/class-lcp-state.php | 18 +++ .../modules/optimizations/lcp/class-lcp.php | 7 + .../rest-api/endpoints/class-update-lcp.php | 20 ++- 9 files changed, 291 insertions(+), 76 deletions(-) create mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss create mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx rename projects/plugins/boost/app/assets/src/js/features/lcp/{lcp.module.scss => status/status.module.scss} (67%) create mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx index b2d96f9fbeac7..4374926ba73cd 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx @@ -1,62 +1,12 @@ -import { __ } from '@wordpress/i18n'; -import styles from './lcp.module.scss'; -import { Button } from '@automattic/jetpack-components'; -import RefreshIcon from '$svg/refresh'; import Module from '$features/module/module'; -import { useLcpState, useOptimizeLcpAction } from './lib/stores/lcp-state'; -import TimeAgo from '$features/critical-css/time-ago/time-ago'; -import { recordBoostEvent } from '$lib/utils/analytics'; import Pill from '$features/ui/pill/pill'; - -const Status = () => { - const [ query ] = useLcpState(); - const lcpState = query?.data; - - if ( lcpState?.status === 'error' ) { - return ( -
- { __( - "An error occurred while optimizing your Cornerstone Page's LCP. Please try again.", - 'jetpack-boost' - ) } -
- ); - } - - if ( lcpState?.status === 'not_analyzed' ) { - // This should never happen, but just in case. - return ( -
- { __( - "Click the optimize button to start optimizing your Cornerstone Page's LCP.", - 'jetpack-boost' - ) } -
- ); - } - - if ( lcpState?.status === 'pending' ) { - return ( -
- { __( - "Jetpack Boost is optimizing your Cornerstone Page's LCP for you.", - 'jetpack-boost' - ) } -
- ); - } - - if ( lcpState?.status !== 'analyzed' || ! lcpState?.updated ) { - return null; - } - - return ( -
- { __( 'Last optimized', 'jetpack-boost' ) }{ ' ' } - . -
- ); -}; +import { recordBoostEvent } from '$lib/utils/analytics'; +import RefreshIcon from '$svg/refresh'; +import { Button } from '@automattic/jetpack-components'; +import { __ } from '@wordpress/i18n'; +import styles from './status/status.module.scss'; +import { useLcpState, useOptimizeLcpAction } from './lib/stores/lcp-state'; +import Status from './status/status'; const Lcp = () => { const [ query ] = useLcpState(); diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/lib/stores/lcp-state-types.ts b/projects/plugins/boost/app/assets/src/js/features/lcp/lib/stores/lcp-state-types.ts index 6d21c9ce7e48d..71d2c547ca8c4 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/lib/stores/lcp-state-types.ts +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/lib/stores/lcp-state-types.ts @@ -1,7 +1,6 @@ -import { JSONSchema } from '$lib/utils/json-types'; import z from 'zod'; -// @TODO: We don't send this back from the API, but it's here for if we do. +// TODO: Reflect this in Boost Cloud after Beta release, each one should be an Error type. export const LcpErrorType = z.enum( [ 'UrlError', 'HttpError', @@ -11,10 +10,7 @@ export const LcpErrorType = z.enum( [ ] ); export const LcpErrorDetailsSchema = z.object( { - url: z.coerce.string(), message: z.coerce.string(), - meta: z.record( JSONSchema ).catch( {} ), - type: LcpErrorType, } ); export const PageSchema = z.object( { @@ -25,7 +21,6 @@ export const PageSchema = z.object( { // Status status: z.enum( [ 'success', 'pending', 'error' ] ).catch( 'pending' ), // Error details - // @TODO: We don't send this back from the API, but it's here for if we do. errors: z.array( LcpErrorDetailsSchema ).optional(), } ); diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss new file mode 100644 index 0000000000000..e676d3d5c8c30 --- /dev/null +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss @@ -0,0 +1,52 @@ +@import '$css/main/variables'; + +$grey: #8e8e8e; +$black: #101517; +$white: #fff; + +.jb-error-tooltip { + background-color: $black; + color: $white; + padding: 16px 24px; + border-radius: 4px; + font-size: 14px; + width: max-content; + max-width: 30rem; + position: absolute; + top: 100%; + left: 50%; + transform: translateX( -50% ); + margin-top: 8px; + box-shadow: 0 1px 2px 0 rgba( 0, 0, 0, 0.05 ); + z-index: 1000; + + hr { + border-top: 1px solid $grey; + border-bottom: none; + border-left: none; + border-right: none; + margin: 12px 0; + } + + &__header { + font-size: 1rem; + font-weight: 600; + } + + &__row { + list-style: disc; + margin: 8px 0 8px 12px; + } + + &__pointer { + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid $black; + position: absolute; + top: -8px; + left: 50%; + transform: translateX( -50% ); + } +} diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx new file mode 100644 index 0000000000000..7a7cac6546e20 --- /dev/null +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx @@ -0,0 +1,30 @@ +import { __ } from '@wordpress/i18n'; +import { type FunctionComponent } from 'react'; +import styles from './error-tooltip.module.scss'; + +interface ErrorTooltipProps { + errors: string[]; +} + +export const ErrorTooltip: FunctionComponent< ErrorTooltipProps > = ( { errors } ) => { + if ( ! errors || errors.length === 0 ) { + return null; + } + + return ( +
+
+ { __( 'Optimization Details', 'jetpack-boost' ) } +
+
+ +
+
+ ); +}; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss similarity index 67% rename from projects/plugins/boost/app/assets/src/js/features/lcp/lcp.module.scss rename to projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss index c14164007bc01..d2b70b91447b1 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss @@ -1,5 +1,5 @@ -@import "$css/main/mixins"; -@import "$css/main/variables"; +@import '$css/main/mixins'; +@import '$css/main/variables'; // TODO: This is a copy of the styles from the critical-css/status component. // We should move this to a shared location. @@ -16,7 +16,7 @@ margin-bottom: 0; } - @include breakpoint(xs) { + @include breakpoint( xs ) { display: block; } @@ -25,10 +25,11 @@ flex-grow: 1; position: relative; - .successes, .generating { + .successes, + .generating { color: $gray_40; - @include breakpoint(md) { + @include breakpoint( md ) { margin-right: 115px; } } @@ -37,7 +38,7 @@ margin-top: 1em; color: $gray_100; - @include breakpoint(xs) { + @include breakpoint( xs ) { margin-bottom: 1em; } @@ -52,7 +53,7 @@ button { - &:global(.components-button.has-icon) { + &:global( .components-button.has-icon ) { min-width: auto; } @@ -61,11 +62,16 @@ } } - .optimize-button:global(.components-button) { + .optimize-button:global( .components-button ) { &:disabled { background: transparent; - opacity: .5; + opacity: 0.5; } } } + +.error-tooltip-wrapper { + position: relative; + display: inline-block; +} \ No newline at end of file diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx new file mode 100644 index 0000000000000..04c017f7e488e --- /dev/null +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx @@ -0,0 +1,145 @@ +import { __, _n, sprintf } from '@wordpress/i18n'; +import clsx from 'clsx'; +import InfoIcon from '$svg/info'; +import { createInterpolateElement, useState } from '@wordpress/element'; +import styles from './status.module.scss'; +import { useLcpState } from '../lib/stores/lcp-state'; +import TimeAgo from '$features/critical-css/time-ago/time-ago'; +import { Button } from '@automattic/jetpack-components'; +import { ErrorTooltip } from './error-tooltip'; + +const ErrorDetails = () => { + const [ query ] = useLcpState(); + const lcpState = query?.data; + + if ( lcpState?.status !== 'analyzed' ) { + return null; + } + + const pages = lcpState?.pages; + if ( ! pages || pages.length === 0 ) { + return null; + } + + const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); + if ( errors.length === 0 ) { + return null; + } + + const errorMessages = errors.flatMap( p => p.errors ); + + return createInterpolateElement( + sprintf( + // translators: %d is a number of pages which failed to be optimized + _n( + '%d page could not be optimized. ', + '%d pages could not be optimized. ', + errorMessages.length, + 'jetpack-boost' + ), + errorMessages.length + ), + { + errorDetails: , + } + ); +}; + +const ErrorDetailsTooltip = () => { + const [ isVisible, setIsVisible ] = useState( false ); + const [ query ] = useLcpState(); + const lcpState = query?.data; + + if ( lcpState?.status !== 'analyzed' ) { + return null; + } + + const pages = lcpState?.pages; + if ( ! pages || pages.length === 0 ) { + return null; + } + + const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); + if ( errors.length === 0 ) { + return null; + } + + const errorMessages = errors.flatMap( p => ( p.errors || [] ).map( e => e.message ) ); + + return ( +
+ + { isVisible && } +
+ ); +}; + +const Status: React.FC = () => { + const [ query ] = useLcpState(); + const lcpState = query?.data; + + if ( lcpState?.status === 'error' ) { + return ( +
+ { __( + "An error occurred while optimizing your Cornerstone Page's LCP. Please try again.", + 'jetpack-boost' + ) } +
+ ); + } + + if ( lcpState?.status === 'not_analyzed' ) { + // This should never happen, but just in case. + return ( +
+ { __( + "Click the optimize button to start optimizing your Cornerstone Page's LCP.", + 'jetpack-boost' + ) } +
+ ); + } + + if ( lcpState?.status === 'pending' ) { + return ( +
+ { __( + "Jetpack Boost is optimizing your Cornerstone Page's LCP for you.", + 'jetpack-boost' + ) } +
+ ); + } + + if ( lcpState?.status !== 'analyzed' || ! lcpState?.updated ) { + return null; + } + + return ( + <> +
+ { __( 'Last optimized', 'jetpack-boost' ) }{ ' ' } + . +
+ { lcpState?.status === 'analyzed' && ( +
+ + + +
+ ) } + + ); +}; + +export default Status; diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-state.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-state.php index 669c48241902a..f353e53fe2987 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-state.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-state.php @@ -112,6 +112,24 @@ public function set_page_success( $page_key ) { $page_key, array( 'status' => self::PAGE_STATES['success'], + 'errors' => null, + ) + ); + } + + /** + * Signifies that the page was not optimized for reason(s) in $errors. + * + * @param string $page_key The page key. + * @param array $errors The errors to set for the page. + * @return bool|\WP_Error True on success, WP_Error on failure. + */ + public function set_page_errors( $page_key, $errors ) { + return $this->update_page_state( + $page_key, + array( + 'status' => self::PAGE_STATES['error'], + 'errors' => $errors, ) ); } diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp.php index 622181abc3f7f..feca54c45ee07 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp.php @@ -161,6 +161,13 @@ public function register_data_sync( $instance ) { 'key' => Schema::as_string(), 'url' => Schema::as_string(), 'status' => Schema::as_string(), + 'errors' => Schema::as_array( + Schema::as_assoc_array( + array( + 'message' => Schema::as_string(), + ) + ) + )->nullable(), ) ) ), diff --git a/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php b/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php index 0636a9a8c8b2e..791645208b291 100644 --- a/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php +++ b/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php @@ -63,12 +63,24 @@ public function response( $request ) { return $api_successful; } - // @TODO: handle bad payload coming from the Cloud. - // Update each page. foreach ( $pages as $entry ) { - // Mark the page as successfully analyzed as we don't know what to do if mobile fails but desktop succeeds. - $state->set_page_success( $entry['key'] ); + if ( $entry['success'] ) { + // Mark the page as successfully analyzed as we don't know what to do if mobile fails but desktop succeeds. + $state->set_page_success( $entry['key'] ); + } else { + $errors = array(); + foreach ( $entry['reports'] as $report ) { + if ( false === $report['success'] && ! empty( $report['message'] ) ) { + $errors[] = array( + // @TODO: Add a type and meta here (and the Cloud) after Beta release to further explain the error. + 'message' => $report['message'] ?? __( 'An unknown error occurred', 'jetpack-boost' ), + ); + } + } + + $state->set_page_errors( $entry['key'], $errors ); + } // Store the LCP data for this page. $storage->store_lcp( $entry['key'], $entry['reports'] ); From 36a9e139950c979aa3dbd048211cf76164d7a800 Mon Sep 17 00:00:00 2001 From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com> Date: Tue, 27 May 2025 18:13:25 +0100 Subject: [PATCH 02/10] Changelog --- .../plugins/boost/changelog/add-boost-lcp-error-messaging | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 projects/plugins/boost/changelog/add-boost-lcp-error-messaging diff --git a/projects/plugins/boost/changelog/add-boost-lcp-error-messaging b/projects/plugins/boost/changelog/add-boost-lcp-error-messaging new file mode 100644 index 0000000000000..85e2e20674008 --- /dev/null +++ b/projects/plugins/boost/changelog/add-boost-lcp-error-messaging @@ -0,0 +1,5 @@ +Significance: patch +Type: added +Comment: LCP: Changes to an unreleased feature. + + From d0c0af9f76453a6df9391bab93f81fa71d92247b Mon Sep 17 00:00:00 2001 From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com> Date: Tue, 27 May 2025 18:39:15 +0100 Subject: [PATCH 03/10] Refactor LCP error handling: Introduce ErrorDetails component * Add ErrorDetails and ErrorDetailsTooltip components for improved error display in LCP status. * Update status.module.scss to reflect changes in error handling structure. --- .../lcp/status/error-details.module.scss | 57 +++++++++ .../js/features/lcp/status/error-details.tsx | 108 ++++++++++++++++++ .../lcp/status/error-tooltip.module.scss | 52 --------- .../js/features/lcp/status/error-tooltip.tsx | 30 ----- .../js/features/lcp/status/status.module.scss | 5 - .../src/js/features/lcp/status/status.tsx | 87 +------------- .../rest-api/endpoints/class-update-lcp.php | 1 - 7 files changed, 170 insertions(+), 170 deletions(-) create mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss create mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx delete mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss delete mode 100644 projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss new file mode 100644 index 0000000000000..6be51596954f7 --- /dev/null +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss @@ -0,0 +1,57 @@ +@import '$css/main/variables'; + +$grey: #8e8e8e; +$black: #101517; +$white: #fff; + +.error-tooltip-wrapper { + position: relative; + display: inline-block; + + .jb-error-tooltip { + background-color: $black; + color: $white; + padding: 16px 24px; + border-radius: 4px; + font-size: 14px; + width: max-content; + max-width: 30rem; + position: absolute; + top: 100%; + left: 50%; + transform: translateX( -50% ); + margin-top: 8px; + box-shadow: 0 1px 2px 0 rgba( 0, 0, 0, 0.05 ); + z-index: 1000; + + hr { + border-top: 1px solid $grey; + border-bottom: none; + border-left: none; + border-right: none; + margin: 12px 0; + } + + &__header { + font-size: 1rem; + font-weight: 600; + } + + &__row { + list-style: disc; + margin: 8px 0 8px 12px; + } + + &__pointer { + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid $black; + position: absolute; + top: -8px; + left: 50%; + transform: translateX( -50% ); + } + } +} diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx new file mode 100644 index 0000000000000..153011ffad954 --- /dev/null +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx @@ -0,0 +1,108 @@ +import { Button } from '@automattic/jetpack-components'; +import { createInterpolateElement } from '@wordpress/element'; +import { __, _n, sprintf } from '@wordpress/i18n'; +import { useState, type FunctionComponent } from 'react'; +import { useLcpState } from '../lib/stores/lcp-state'; +import styles from './error-details.module.scss'; + +interface ErrorTooltipProps { + errors: string[]; +} + +export const ErrorDetails = () => { + const [ query ] = useLcpState(); + const lcpState = query?.data; + + if ( lcpState?.status !== 'analyzed' ) { + return null; + } + + const pages = lcpState?.pages; + if ( ! pages || pages.length === 0 ) { + return null; + } + + const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); + if ( errors.length === 0 ) { + return null; + } + + const errorMessages = errors.flatMap( p => p.errors ); + + return createInterpolateElement( + sprintf( + // translators: %d is a number of pages which failed to be optimized + _n( + '%d page could not be optimized. ', + '%d pages could not be optimized. ', + errorMessages.length, + 'jetpack-boost' + ), + errorMessages.length + ), + { + errorDetails: , + } + ); +}; + +export const ErrorDetailsTooltip = () => { + const [ isVisible, setIsVisible ] = useState( false ); + const [ query ] = useLcpState(); + const lcpState = query?.data; + + if ( lcpState?.status !== 'analyzed' ) { + return null; + } + + const pages = lcpState?.pages; + if ( ! pages || pages.length === 0 ) { + return null; + } + + const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); + if ( errors.length === 0 ) { + return null; + } + + const errorMessages = errors.flatMap( p => ( p.errors || [] ).map( e => e.message ) ); + + return ( +
+ + { isVisible && } +
+ ); +}; + +export const ErrorTooltip: FunctionComponent< ErrorTooltipProps > = ( { errors } ) => { + if ( ! errors || errors.length === 0 ) { + return null; + } + + return ( +
+
+ { __( 'Optimization Details', 'jetpack-boost' ) } +
+
+
    + { errors.map( ( error, index ) => ( +
  • + { error } +
  • + ) ) } +
+
+
+ ); +}; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss deleted file mode 100644 index e676d3d5c8c30..0000000000000 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.module.scss +++ /dev/null @@ -1,52 +0,0 @@ -@import '$css/main/variables'; - -$grey: #8e8e8e; -$black: #101517; -$white: #fff; - -.jb-error-tooltip { - background-color: $black; - color: $white; - padding: 16px 24px; - border-radius: 4px; - font-size: 14px; - width: max-content; - max-width: 30rem; - position: absolute; - top: 100%; - left: 50%; - transform: translateX( -50% ); - margin-top: 8px; - box-shadow: 0 1px 2px 0 rgba( 0, 0, 0, 0.05 ); - z-index: 1000; - - hr { - border-top: 1px solid $grey; - border-bottom: none; - border-left: none; - border-right: none; - margin: 12px 0; - } - - &__header { - font-size: 1rem; - font-weight: 600; - } - - &__row { - list-style: disc; - margin: 8px 0 8px 12px; - } - - &__pointer { - width: 0; - height: 0; - border-left: 8px solid transparent; - border-right: 8px solid transparent; - border-bottom: 8px solid $black; - position: absolute; - top: -8px; - left: 50%; - transform: translateX( -50% ); - } -} diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx deleted file mode 100644 index 7a7cac6546e20..0000000000000 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-tooltip.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { __ } from '@wordpress/i18n'; -import { type FunctionComponent } from 'react'; -import styles from './error-tooltip.module.scss'; - -interface ErrorTooltipProps { - errors: string[]; -} - -export const ErrorTooltip: FunctionComponent< ErrorTooltipProps > = ( { errors } ) => { - if ( ! errors || errors.length === 0 ) { - return null; - } - - return ( -
-
- { __( 'Optimization Details', 'jetpack-boost' ) } -
-
-
    - { errors.map( ( error, index ) => ( -
  • - { error } -
  • - ) ) } -
-
-
- ); -}; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss index d2b70b91447b1..ff394c604b6bb 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss @@ -70,8 +70,3 @@ } } } - -.error-tooltip-wrapper { - position: relative; - display: inline-block; -} \ No newline at end of file diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx index 04c017f7e488e..212c1cae1aecf 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx @@ -1,87 +1,10 @@ -import { __, _n, sprintf } from '@wordpress/i18n'; -import clsx from 'clsx'; +import TimeAgo from '$features/critical-css/time-ago/time-ago'; import InfoIcon from '$svg/info'; -import { createInterpolateElement, useState } from '@wordpress/element'; -import styles from './status.module.scss'; +import { __ } from '@wordpress/i18n'; +import clsx from 'clsx'; import { useLcpState } from '../lib/stores/lcp-state'; -import TimeAgo from '$features/critical-css/time-ago/time-ago'; -import { Button } from '@automattic/jetpack-components'; -import { ErrorTooltip } from './error-tooltip'; - -const ErrorDetails = () => { - const [ query ] = useLcpState(); - const lcpState = query?.data; - - if ( lcpState?.status !== 'analyzed' ) { - return null; - } - - const pages = lcpState?.pages; - if ( ! pages || pages.length === 0 ) { - return null; - } - - const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); - if ( errors.length === 0 ) { - return null; - } - - const errorMessages = errors.flatMap( p => p.errors ); - - return createInterpolateElement( - sprintf( - // translators: %d is a number of pages which failed to be optimized - _n( - '%d page could not be optimized. ', - '%d pages could not be optimized. ', - errorMessages.length, - 'jetpack-boost' - ), - errorMessages.length - ), - { - errorDetails: , - } - ); -}; - -const ErrorDetailsTooltip = () => { - const [ isVisible, setIsVisible ] = useState( false ); - const [ query ] = useLcpState(); - const lcpState = query?.data; - - if ( lcpState?.status !== 'analyzed' ) { - return null; - } - - const pages = lcpState?.pages; - if ( ! pages || pages.length === 0 ) { - return null; - } - - const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); - if ( errors.length === 0 ) { - return null; - } - - const errorMessages = errors.flatMap( p => ( p.errors || [] ).map( e => e.message ) ); - - return ( -
- - { isVisible && } -
- ); -}; +import { ErrorDetails } from './error-details'; +import styles from './status.module.scss'; const Status: React.FC = () => { const [ query ] = useLcpState(); diff --git a/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php b/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php index 791645208b291..471796de1df42 100644 --- a/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php +++ b/projects/plugins/boost/app/rest-api/endpoints/class-update-lcp.php @@ -66,7 +66,6 @@ public function response( $request ) { // Update each page. foreach ( $pages as $entry ) { if ( $entry['success'] ) { - // Mark the page as successfully analyzed as we don't know what to do if mobile fails but desktop succeeds. $state->set_page_success( $entry['key'] ); } else { $errors = array(); From 7521e688c671946296f72aaff1e227c585ef9a60 Mon Sep 17 00:00:00 2001 From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com> Date: Tue, 27 May 2025 18:57:48 +0100 Subject: [PATCH 04/10] Enhance LCP background image optimization: Add conditional optimization checks * Introduce checks to determine if background images can be optimized before processing. * Refactor logic to skip elements that do not meet optimization criteria. --- .../lcp/class-lcp-optimize-bg-image.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php index bd7d083db3940..3a9331027469b 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php @@ -41,6 +41,11 @@ public function preload_background_images() { $selectors = array(); foreach ( $this->lcp_data as $lcp_data ) { + $lcp_optimizer = new LCP_Optimization_Util( $lcp_data ); + if ( ! $lcp_optimizer->can_optimize() ) { + continue; + } + if ( in_array( $lcp_data['element'], $selectors, true ) ) { // If we already printed the styling for this element, skip it. continue; @@ -74,14 +79,18 @@ public function add_bg_style_override() { $selectors = array(); foreach ( $this->lcp_data as $lcp_data ) { + $lcp_optimizer = new LCP_Optimization_Util( $lcp_data ); + if ( ! $lcp_optimizer->can_optimize() ) { + continue; + } + if ( in_array( $lcp_data['element'], $selectors, true ) ) { // If we already printed the styling for this element, skip it. continue; } $selectors[] = $lcp_data['element']; - $lcp_optimizer = new LCP_Optimization_Util( $lcp_data ); - $image_url = $lcp_optimizer->get_image_to_preload(); + $image_url = $lcp_optimizer->get_image_to_preload(); if ( empty( $image_url ) ) { continue; } From 7822175bb76cd3381f5522a7f918c9c022209a06 Mon Sep 17 00:00:00 2001 From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com> Date: Wed, 28 May 2025 10:17:34 +0100 Subject: [PATCH 05/10] Refactor LCP error display: Update ErrorDetails component and styles * Enhance the ErrorDetails component to include a summary wrapper for better layout. * Refactor SCSS styles for error tooltips and summary display, improving visual consistency. * Simplify the rendering logic in the Status component by directly integrating ErrorDetails. --- .../lcp/status/error-details.module.scss | 101 ++++++++++-------- .../js/features/lcp/status/error-details.tsx | 32 +++--- .../js/features/lcp/status/status.module.scss | 16 --- .../src/js/features/lcp/status/status.tsx | 10 +- 4 files changed, 78 insertions(+), 81 deletions(-) diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss index 6be51596954f7..f5c5556f82978 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss @@ -1,57 +1,74 @@ +@import '$css/main/mixins'; @import '$css/main/variables'; $grey: #8e8e8e; $black: #101517; $white: #fff; -.error-tooltip-wrapper { - position: relative; - display: inline-block; - - .jb-error-tooltip { - background-color: $black; - color: $white; - padding: 16px 24px; - border-radius: 4px; - font-size: 14px; - width: max-content; - max-width: 30rem; - position: absolute; - top: 100%; - left: 50%; - transform: translateX( -50% ); - margin-top: 8px; - box-shadow: 0 1px 2px 0 rgba( 0, 0, 0, 0.05 ); - z-index: 1000; - - hr { - border-top: 1px solid $grey; - border-bottom: none; - border-left: none; - border-right: none; - margin: 12px 0; - } +.summary { + margin-top: 1em; + color: $gray_100; - &__header { - font-size: 1rem; - font-weight: 600; - } + @include breakpoint( xs ) { + margin-bottom: 1em; + } - &__row { - list-style: disc; - margin: 8px 0 8px 12px; - } + svg { + position: absolute; + width: 1.4rem; + height: 1.4rem; + left: -60px; + } + + .error-tooltip-wrapper { + position: relative; + display: inline-block; - &__pointer { - width: 0; - height: 0; - border-left: 8px solid transparent; - border-right: 8px solid transparent; - border-bottom: 8px solid $black; + .jb-error-tooltip { + background-color: $black; + color: $white; + padding: 16px 24px; + border-radius: 4px; + font-size: 14px; + width: max-content; + max-width: 30rem; position: absolute; - top: -8px; + top: 100%; left: 50%; transform: translateX( -50% ); + margin-top: 8px; + box-shadow: 0 1px 2px 0 rgba( 0, 0, 0, 0.05 ); + z-index: 1000; + + hr { + border-top: 1px solid $grey; + border-bottom: none; + border-left: none; + border-right: none; + margin: 12px 0; + } + + &__header { + font-size: 1rem; + font-weight: 600; + } + + &__row { + list-style: disc; + margin: 8px 0 8px 12px; + } + + &__pointer { + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid $black; + position: absolute; + top: -8px; + left: 50%; + transform: translateX( -50% ); + } } } } diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx index 153011ffad954..3112abbfc524a 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx @@ -29,20 +29,24 @@ export const ErrorDetails = () => { const errorMessages = errors.flatMap( p => p.errors ); - return createInterpolateElement( - sprintf( - // translators: %d is a number of pages which failed to be optimized - _n( - '%d page could not be optimized. ', - '%d pages could not be optimized. ', - errorMessages.length, - 'jetpack-boost' - ), - errorMessages.length - ), - { - errorDetails: , - } + return ( +
+ { createInterpolateElement( + sprintf( + // translators: %d is a number of pages which failed to be optimized + _n( + '%d page could not be optimized. ', + '%d pages could not be optimized. ', + errorMessages.length, + 'jetpack-boost' + ), + errorMessages.length + ), + { + errorDetails: , + } + ) } +
); }; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss index ff394c604b6bb..931e8bbbc85a2 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss @@ -33,22 +33,6 @@ margin-right: 115px; } } - - .failures { - margin-top: 1em; - color: $gray_100; - - @include breakpoint( xs ) { - margin-bottom: 1em; - } - - svg { - position: absolute; - width: 1.4rem; - height: 1.4rem; - left: -60px; - } - } } button { diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx index 212c1cae1aecf..ae90d2ad87360 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx @@ -1,7 +1,5 @@ import TimeAgo from '$features/critical-css/time-ago/time-ago'; -import InfoIcon from '$svg/info'; import { __ } from '@wordpress/i18n'; -import clsx from 'clsx'; import { useLcpState } from '../lib/stores/lcp-state'; import { ErrorDetails } from './error-details'; import styles from './status.module.scss'; @@ -54,13 +52,7 @@ const Status: React.FC = () => { { __( 'Last optimized', 'jetpack-boost' ) }{ ' ' } . - { lcpState?.status === 'analyzed' && ( -
- - - -
- ) } + { lcpState?.status === 'analyzed' && } ); }; From 4c28ed332b07696700704f5bf3e3a1f4b178faa6 Mon Sep 17 00:00:00 2001 From: Adnan Haque Date: Wed, 28 May 2025 16:09:21 -0400 Subject: [PATCH 06/10] Use property instead of --- .../optimizations/lcp/class-lcp-optimization-util.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php index eca9b81d46df6..ff75f09c55fca 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php @@ -102,19 +102,15 @@ public function get_image_to_preload() { return null; } - if ( empty( $this->lcp_data['elementData'] ) || ! is_array( $this->lcp_data['elementData'] ) ) { + if ( empty( $this->lcp_data['url'] ) ) { return null; } - if ( empty( $this->lcp_data['elementData']['url'] ) ) { + if ( ! wp_http_validate_url( $this->lcp_data['url'] ) ) { return null; } - if ( ! wp_http_validate_url( $this->lcp_data['elementData']['url'] ) ) { - return null; - } - - return $this->lcp_data['elementData']['url']; + return $this->lcp_data['url']; } /** From 6c6921797d0c19f4cfe2991148715fbb44906f83 Mon Sep 17 00:00:00 2001 From: Adnan Haque Date: Wed, 28 May 2025 16:11:34 -0400 Subject: [PATCH 07/10] Rename lcp image URL method and make it reusable --- .../optimizations/lcp/class-lcp-optimization-util.php | 4 ++-- .../optimizations/lcp/class-lcp-optimize-bg-image.php | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php index ff75f09c55fca..4ee676a31e94d 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php @@ -93,12 +93,12 @@ public static function should_skip_optimization() { return false; } - public function get_image_to_preload() { + public function get_lcp_image_url() { if ( ! $this->can_optimize() ) { return null; } - if ( LCP::TYPE_BACKGROUND_IMAGE !== $this->lcp_data['type'] ) { + if ( LCP::TYPE_BACKGROUND_IMAGE !== $this->lcp_data['type'] && LCP::TYPE_IMAGE !== $this->lcp_data['type'] ) { return null; } diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php index bd7d083db3940..4b9a948171c6e 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php @@ -81,7 +81,7 @@ public function add_bg_style_override() { $selectors[] = $lcp_data['element']; $lcp_optimizer = new LCP_Optimization_Util( $lcp_data ); - $image_url = $lcp_optimizer->get_image_to_preload(); + $image_url = $lcp_optimizer->get_lcp_image_url(); if ( empty( $image_url ) ) { continue; } @@ -118,12 +118,12 @@ public function add_bg_style_override() { } private function get_responsive_image_rules( $lcp_data ) { - if ( empty( $lcp_data['breakpoints'] ) ) { + if ( $lcp_data['type'] !== LCP::TYPE_BACKGROUND_IMAGE || empty( $lcp_data['breakpoints'] ) ) { return array(); } $lcp_optimizer = new LCP_Optimization_Util( $lcp_data ); - $image_url = $lcp_optimizer->get_image_to_preload(); + $image_url = $lcp_optimizer->get_lcp_image_url(); if ( empty( $image_url ) ) { return array(); From c7a8b107d584bb1c559e2f839eb823bfcf2686f4 Mon Sep 17 00:00:00 2001 From: Adnan Haque Date: Wed, 28 May 2025 16:21:58 -0400 Subject: [PATCH 08/10] changelog --- projects/plugins/boost/changelog/update-lcp-bg-url-property | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 projects/plugins/boost/changelog/update-lcp-bg-url-property diff --git a/projects/plugins/boost/changelog/update-lcp-bg-url-property b/projects/plugins/boost/changelog/update-lcp-bg-url-property new file mode 100644 index 0000000000000..5b0bbf6c6cbbc --- /dev/null +++ b/projects/plugins/boost/changelog/update-lcp-bg-url-property @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Unreleased feature + + From 5531637e74dc391a20114ad64c2cc2b2d42b69f7 Mon Sep 17 00:00:00 2001 From: Liam Sarsfield <43409125+LiamSarsfield@users.noreply.github.com> Date: Thu, 29 May 2025 13:09:29 +0100 Subject: [PATCH 09/10] Refactor LCP error handling: Update ErrorDetails component and styles * Integrate FoldingElement for better error message display in the ErrorDetails component. * Simplify error message rendering and enhance user interaction with expandable details. * Adjust SCSS styles for improved layout and visual consistency in error summaries. --- .../folding-element/folding-element.tsx | 8 +- .../app/assets/src/js/features/lcp/lcp.tsx | 2 + .../lcp/status/error-details.module.scss | 72 ++---------- .../js/features/lcp/status/error-details.tsx | 111 +++++------------- .../js/features/lcp/status/status.module.scss | 6 +- .../src/js/features/lcp/status/status.tsx | 2 - 6 files changed, 49 insertions(+), 152 deletions(-) diff --git a/projects/plugins/boost/app/assets/src/js/features/critical-css/folding-element/folding-element.tsx b/projects/plugins/boost/app/assets/src/js/features/critical-css/folding-element/folding-element.tsx index 308f048b56f81..293e0c005044c 100644 --- a/projects/plugins/boost/app/assets/src/js/features/critical-css/folding-element/folding-element.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/critical-css/folding-element/folding-element.tsx @@ -1,11 +1,11 @@ -import useMeasure from 'react-use-measure'; +import ChevronDown from '$svg/chevron-down'; +import ChevronUp from '$svg/chevron-up'; +import { Button } from '@automattic/jetpack-components'; import { animated, useSpring } from '@react-spring/web'; import clsx from 'clsx'; import { useState } from 'react'; -import ChevronDown from '$svg/chevron-down'; -import ChevronUp from '$svg/chevron-up'; +import useMeasure from 'react-use-measure'; import styles from './folding-element.module.scss'; -import { Button } from '@automattic/jetpack-components'; type PropTypes = { labelExpandedText: string; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx index 4374926ba73cd..a0b4a54b83782 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/lcp.tsx @@ -7,6 +7,7 @@ import { __ } from '@wordpress/i18n'; import styles from './status/status.module.scss'; import { useLcpState, useOptimizeLcpAction } from './lib/stores/lcp-state'; import Status from './status/status'; +import { ErrorDetails } from './status/error-details'; const Lcp = () => { const [ query ] = useLcpState(); @@ -59,6 +60,7 @@ const Lcp = () => { { __( 'Optimize', 'jetpack-boost' ) } + { lcpState?.status === 'analyzed' && } ); }; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss index f5c5556f82978..30d42e39112f2 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.module.scss @@ -1,74 +1,22 @@ @import '$css/main/mixins'; -@import '$css/main/variables'; - -$grey: #8e8e8e; -$black: #101517; -$white: #fff; .summary { - margin-top: 1em; - color: $gray_100; + margin-top: 16px; + margin-bottom: 16px; @include breakpoint( xs ) { margin-bottom: 1em; } - svg { - position: absolute; - width: 1.4rem; - height: 1.4rem; - left: -60px; + &__list { + display: flex; + flex-direction: column; + gap: 8px; } - .error-tooltip-wrapper { - position: relative; - display: inline-block; - - .jb-error-tooltip { - background-color: $black; - color: $white; - padding: 16px 24px; - border-radius: 4px; - font-size: 14px; - width: max-content; - max-width: 30rem; - position: absolute; - top: 100%; - left: 50%; - transform: translateX( -50% ); - margin-top: 8px; - box-shadow: 0 1px 2px 0 rgba( 0, 0, 0, 0.05 ); - z-index: 1000; - - hr { - border-top: 1px solid $grey; - border-bottom: none; - border-left: none; - border-right: none; - margin: 12px 0; - } - - &__header { - font-size: 1rem; - font-weight: 600; - } - - &__row { - list-style: disc; - margin: 8px 0 8px 12px; - } - - &__pointer { - width: 0; - height: 0; - border-left: 8px solid transparent; - border-right: 8px solid transparent; - border-bottom: 8px solid $black; - position: absolute; - top: -8px; - left: 50%; - transform: translateX( -50% ); - } - } + &__row { + list-style: disc; + margin-bottom: 0; + margin-left: 20px; } } diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx index 3112abbfc524a..a751535f212aa 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/error-details.tsx @@ -1,14 +1,10 @@ -import { Button } from '@automattic/jetpack-components'; -import { createInterpolateElement } from '@wordpress/element'; +import FoldingElement from '$features/critical-css/folding-element/folding-element'; +import { recordBoostEvent } from '$lib/utils/analytics'; +import { Notice } from '@automattic/jetpack-components'; import { __, _n, sprintf } from '@wordpress/i18n'; -import { useState, type FunctionComponent } from 'react'; import { useLcpState } from '../lib/stores/lcp-state'; import styles from './error-details.module.scss'; -interface ErrorTooltipProps { - errors: string[]; -} - export const ErrorDetails = () => { const [ query ] = useLcpState(); const lcpState = query?.data; @@ -27,86 +23,43 @@ export const ErrorDetails = () => { return null; } - const errorMessages = errors.flatMap( p => p.errors ); + const errorMessages = errors.flatMap( p => ( p.errors || [] ).map( e => e.message ) ); return ( -
- { createInterpolateElement( - sprintf( + +
+ { sprintf( // translators: %d is a number of pages which failed to be optimized _n( - '%d page could not be optimized. ', - '%d pages could not be optimized. ', + '%d page could not be optimized.', + '%d pages could not be optimized.', errorMessages.length, 'jetpack-boost' ), errorMessages.length - ), - { - errorDetails: , - } - ) } -
- ); -}; - -export const ErrorDetailsTooltip = () => { - const [ isVisible, setIsVisible ] = useState( false ); - const [ query ] = useLcpState(); - const lcpState = query?.data; - - if ( lcpState?.status !== 'analyzed' ) { - return null; - } - - const pages = lcpState?.pages; - if ( ! pages || pages.length === 0 ) { - return null; - } - - const errors = pages.filter( page => ( page?.errors?.length || 0 ) > 0 ); - if ( errors.length === 0 ) { - return null; - } - - const errorMessages = errors.flatMap( p => ( p.errors || [] ).map( e => e.message ) ); - - return ( -
- - { isVisible && } -
- ); -}; - -export const ErrorTooltip: FunctionComponent< ErrorTooltipProps > = ( { errors } ) => { - if ( ! errors || errors.length === 0 ) { - return null; - } - - return ( -
-
- { __( 'Optimization Details', 'jetpack-boost' ) } + ) }
-
-
    - { errors.map( ( error, index ) => ( -
  • - { error } -
  • - ) ) } -
-
-
+ { + if ( isExpanded ) { + recordBoostEvent( 'lcp_error_details_expanded', {} ); + } + } } + > +
    + { errorMessages.map( ( error, index ) => ( +
  • + { error } +
  • + ) ) } +
+
+
); }; diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss index 931e8bbbc85a2..c923bdb017500 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.module.scss @@ -5,7 +5,7 @@ // We should move this to a shared location. .status { - margin-bottom: 32px; + margin-bottom: 16px; font-size: 14px; line-height: 22px; display: flex; @@ -40,10 +40,6 @@ &:global( .components-button.has-icon ) { min-width: auto; } - - svg { - fill: $jetpack-green; - } } .optimize-button:global( .components-button ) { diff --git a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx index ae90d2ad87360..d0a2d989dd05a 100644 --- a/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/lcp/status/status.tsx @@ -1,7 +1,6 @@ import TimeAgo from '$features/critical-css/time-ago/time-ago'; import { __ } from '@wordpress/i18n'; import { useLcpState } from '../lib/stores/lcp-state'; -import { ErrorDetails } from './error-details'; import styles from './status.module.scss'; const Status: React.FC = () => { @@ -52,7 +51,6 @@ const Status: React.FC = () => { { __( 'Last optimized', 'jetpack-boost' ) }{ ' ' } .
- { lcpState?.status === 'analyzed' && } ); }; From 1c3e4ee4f442cf8abd365b8f4daa88d7b4849d13 Mon Sep 17 00:00:00 2001 From: Adnan Haque Date: Thu, 29 May 2025 11:22:15 -0400 Subject: [PATCH 10/10] Use `selector` instead of `element` property --- .../optimizations/lcp/class-lcp-optimization-util.php | 2 +- .../optimizations/lcp/class-lcp-optimize-bg-image.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php index 4ee676a31e94d..403bcc86aae0d 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimization-util.php @@ -110,7 +110,7 @@ public function get_lcp_image_url() { return null; } - return $this->lcp_data['url']; + return $this->lcp_data['url']; } /** diff --git a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php index 4b9a948171c6e..cb7f5087aaafa 100644 --- a/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php +++ b/projects/plugins/boost/app/modules/optimizations/lcp/class-lcp-optimize-bg-image.php @@ -41,11 +41,11 @@ public function preload_background_images() { $selectors = array(); foreach ( $this->lcp_data as $lcp_data ) { - if ( in_array( $lcp_data['element'], $selectors, true ) ) { + if ( in_array( $lcp_data['selector'], $selectors, true ) ) { // If we already printed the styling for this element, skip it. continue; } - $selectors[] = $lcp_data['element']; + $selectors[] = $lcp_data['selector']; $responsive_image_rules = $this->get_responsive_image_rules( $lcp_data ); $this->print_preload_links( $responsive_image_rules ); @@ -74,11 +74,11 @@ public function add_bg_style_override() { $selectors = array(); foreach ( $this->lcp_data as $lcp_data ) { - if ( in_array( $lcp_data['element'], $selectors, true ) ) { + if ( in_array( $lcp_data['selector'], $selectors, true ) ) { // If we already printed the styling for this element, skip it. continue; } - $selectors[] = $lcp_data['element']; + $selectors[] = $lcp_data['selector']; $lcp_optimizer = new LCP_Optimization_Util( $lcp_data ); $image_url = $lcp_optimizer->get_lcp_image_url(); @@ -101,7 +101,7 @@ public function add_bg_style_override() { $styles[] = sprintf( '@media %1$s { %2$s { background-image: url(%3$s) !important; background-image: -webkit-image-set(%4$s) !important; background-image: image-set(%4$s) !important; } }', $breakpoint['media_query'], - $lcp_data['element'], + $lcp_data['selector'], $breakpoint['base_image'], $image_set_string );