From 7d70d7168031cbdfb9cb1e996c2bc7f9e1d070e6 Mon Sep 17 00:00:00 2001 From: Brandon Kraft Date: Thu, 8 Oct 2026 14:42:37 -0500 Subject: [PATCH 1/2] Protect Dashboard: Tell the Monitor card's failures apart The uptime route returns three errors and the Overview card showed the same text for all of them. A user without a WordPress.com connection now gets a link to connect, Monitor being turned off elsewhere shows the Off state, and a WordPress.com failure gets a Try again button that skips the failure cached for a minute. --- ...t-monitor-card-failure-states-JETPACK-2963 | 4 + .../sections/monitor/monitor-card.tsx | 83 ++++++++++++++----- .../monitor/test/monitor-card.test.tsx | 68 +++++++++++++-- .../protect/src/sections/class-monitor.php | 13 ++- .../protect/tests/php/Monitor_Test.php | 12 +++ ...t-monitor-card-failure-states-JETPACK-2963 | 4 + 6 files changed, 157 insertions(+), 27 deletions(-) create mode 100644 projects/packages/protect/changelog/update-protect-monitor-card-failure-states-JETPACK-2963 create mode 100644 projects/plugins/jetpack/changelog/update-protect-monitor-card-failure-states-JETPACK-2963 diff --git a/projects/packages/protect/changelog/update-protect-monitor-card-failure-states-JETPACK-2963 b/projects/packages/protect/changelog/update-protect-monitor-card-failure-states-JETPACK-2963 new file mode 100644 index 00000000000..d41913b1cc5 --- /dev/null +++ b/projects/packages/protect/changelog/update-protect-monitor-card-failure-states-JETPACK-2963 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Protect dashboard: Tell the Monitor card's failures apart, with a link to connect a WordPress.com account and a way to retry. diff --git a/projects/packages/protect/routes/dashboard/sections/monitor/monitor-card.tsx b/projects/packages/protect/routes/dashboard/sections/monitor/monitor-card.tsx index 21d151a19e8..d91c99d6327 100644 --- a/projects/packages/protect/routes/dashboard/sections/monitor/monitor-card.tsx +++ b/projects/packages/protect/routes/dashboard/sections/monitor/monitor-card.tsx @@ -1,9 +1,9 @@ import apiFetch from '@wordpress/api-fetch'; import { getSettings, gmdateI18n } from '@wordpress/date'; -import { useEffect, useState } from '@wordpress/element'; +import { useCallback, useEffect, useState } from '@wordpress/element'; import { __, _n, sprintf } from '@wordpress/i18n'; import { seen } from '@wordpress/icons'; -import { Skeleton, Stack, Text, VisuallyHidden } from '@wordpress/ui'; +import { Button, Link, Skeleton, Stack, Text, VisuallyHidden } from '@wordpress/ui'; import { CardRow, ProtectCard } from '../../components/card'; import SettingsLink from '../../components/settings-link'; import isModuleActive from '../../data/is-module-active'; @@ -11,6 +11,9 @@ import type { MonitorContext, Uptime, UptimeDay } from './types'; import type { CardStatus } from '../../components/card'; import './style.scss'; +const UPTIME_PATH = '/jetpack/v4/protect-dashboard/uptime'; +const CONNECT_URL = 'admin.php?page=my-jetpack#/connection'; + /** * Text for one day's bar. * @@ -46,6 +49,7 @@ function describeDay( day: UptimeDay ): string { * * @param available - Whether Monitor can run on this site. * @param active - Whether Monitor is on. + * @param connected - Whether the user has a WordPress.com connection. * @param uptime - The uptime response, once loaded. * @param failed - Whether loading it failed. * @return The badge, if any. @@ -53,6 +57,7 @@ function describeDay( day: UptimeDay ): string { function getStatus( available: boolean, active: boolean, + connected: boolean, uptime: Uptime | null, failed: boolean ): CardStatus | undefined { @@ -62,6 +67,9 @@ function getStatus( if ( ! active ) { return { label: __( 'Off', 'jetpack-protect-pkg' ), intent: 'draft' }; } + if ( ! connected ) { + return { label: __( 'On', 'jetpack-protect-pkg' ), intent: 'none' }; + } if ( uptime?.isUp === true ) { return { label: __( 'Operational', 'jetpack-protect-pkg' ), intent: 'stable' }; } @@ -90,23 +98,36 @@ export default function MonitorCard( { state: monitor, settings, openSettings }: available && ! settings.isSaving( 'monitor' ) && isModuleActive( settings.settings, 'monitor', Boolean( monitor?.active ) ); + const { refresh } = settings; const [ uptime, setUptime ] = useState< Uptime | null >( null ); - const [ failed, setFailed ] = useState( false ); + const [ error, setError ] = useState< string | null >( null ); + const [ retries, setRetries ] = useState( 0 ); + const connected = Boolean( monitor?.userConnected ) && error !== 'not_connected'; + const failed = connected && error !== null; + const canLoad = active && Boolean( monitor?.userConnected ); + const retry = useCallback( () => setRetries( count => count + 1 ), [] ); useEffect( () => { - if ( ! active ) { + if ( ! canLoad ) { return; } let current = true; setUptime( null ); - setFailed( false ); - apiFetch< Uptime >( { path: '/jetpack/v4/protect-dashboard/uptime' } ) + setError( null ); + // A retry skips the failure the server remembers for a minute. + apiFetch< Uptime >( { path: retries ? `${ UPTIME_PATH }?retry=1` : UPTIME_PATH } ) .then( response => current && setUptime( response ) ) - .catch( () => current && setFailed( true ) ); + .catch( async ( e: { code?: string } ) => { + // Monitor was turned off elsewhere: re-read it so the card and its toggle show Off. + if ( e?.code === 'monitor_inactive' ) { + await refresh( [ 'monitor' ] ); + } + return current && setError( e?.code ?? 'uptime_unavailable' ); + } ); return () => { current = false; }; - }, [ active ] ); + }, [ canLoad, retries, refresh ] ); const days = uptime?.days; const count = ( status: UptimeDay[ 'status' ] ) => @@ -144,26 +165,48 @@ export default function MonitorCard( { state: monitor, settings, openSettings }: { ! active && { body } } { active && ( - - { sprintf( - /* translators: %d is a number of days. */ - __( 'Uptime, last %d days (UTC)', 'jetpack-protect-pkg' ), - days?.length ?? monitor?.uptimeDays ?? 0 - ) } - - { failed && ( + { connected && ( - { __( 'Uptime history is unavailable right now.', 'jetpack-protect-pkg' ) } + { sprintf( + /* translators: %d is a number of days. */ + __( 'Uptime, last %d days (UTC)', 'jetpack-protect-pkg' ), + days?.length ?? monitor?.uptimeDays ?? 0 + ) } ) } - { ! failed && ! days && } - { ! failed && days && ( + { ! connected && ( + <> + + { __( + 'Your site is being monitored. Connect your WordPress.com account to see its uptime history.', + 'jetpack-protect-pkg' + ) } + + + { __( 'Connect your account', 'jetpack-protect-pkg' ) } + + + ) } + { failed && ( + + + { __( 'Uptime history is unavailable right now.', 'jetpack-protect-pkg' ) } + + + + ) } + { connected && ! failed && ! days && ( + + ) } + { connected && ! failed && days && ( <>