@@ -42,13 +121,23 @@ const Summary = () => {
-
- { sprintf(
- /* translators: %s: Latest check date */
- __( 'Latest results as of %s', 'jetpack-protect' ),
- dateI18n( 'F jS', lastChecked )
- ) }
-
+ { ! viewingScanHistory ? (
+
+ { sprintf(
+ /* translators: %s: Latest check date */
+ __( 'Latest results as of %s', 'jetpack-protect' ),
+ dateI18n( 'F jS', lastChecked )
+ ) }
+
+ ) : (
+
+ { sprintf(
+ /* translators: %s: Filter applied */
+ __( 'Scan history of %s threats', 'jetpack-protect' ),
+ filter
+ ) }
+
+ ) }
{ ! hasRequiredPlan && (
{
) }
- { hasRequiredPlan && numThreats === 0 && (
+ { hasRequiredPlan && (
<>
-
-
+ { ! viewingScanHistory && numThreats === 0 && renderScanOptions() }
+ { viewingScanHistory && renderHistoryButtons() }
>
) }
diff --git a/projects/plugins/protect/src/js/components/summary/styles.module.scss b/projects/plugins/protect/src/js/components/summary/styles.module.scss
index de1f850e4934a..e72a61b7c0bfd 100644
--- a/projects/plugins/protect/src/js/components/summary/styles.module.scss
+++ b/projects/plugins/protect/src/js/components/summary/styles.module.scss
@@ -5,7 +5,7 @@
@media ( min-width: 960px ) {
display: flex;
- align-items: center;
+ align-items: flex-start;
}
}
@@ -20,7 +20,7 @@
margin-right: var( --spacing-base ); // 8px
}
-.summary__scan-button {
+.summary__scan-button, .summary__history-button {
margin-top: calc( var( --spacing-base ) * 2 ); // 16px
width: 100%;
diff --git a/projects/plugins/protect/src/js/components/threats-list/empty.jsx b/projects/plugins/protect/src/js/components/threats-list/empty.jsx
index 9ba2b3941d499..18c6d801953d8 100644
--- a/projects/plugins/protect/src/js/components/threats-list/empty.jsx
+++ b/projects/plugins/protect/src/js/components/threats-list/empty.jsx
@@ -3,6 +3,7 @@ import { createInterpolateElement } from '@wordpress/element';
import { sprintf, __, _n } from '@wordpress/i18n';
import { useMemo } from 'react';
import useProtectData from '../../hooks/use-protect-data';
+import useScanHistory from '../../hooks/use-scan-history';
import styles from './styles.module.scss';
const ProtectCheck = () => (
@@ -84,6 +85,7 @@ const timeSince = date => {
const EmptyList = () => {
const { lastChecked } = useProtectData();
+ const { viewingScanHistory } = useScanHistory();
const timeSinceLastScan = useMemo( () => {
return lastChecked ? timeSince( Date.parse( lastChecked ) ) : null;
@@ -96,19 +98,24 @@ const EmptyList = () => {
{ __( "Don't worry about a thing", 'jetpack-protect' ) }
- { createInterpolateElement(
- sprintf(
- // translators: placeholder is the amount of time since the last scan, i.e. "5 minutes ago".
- __(
- 'The last Protect scan ran %s and everything looked great.',
+ { viewingScanHistory
+ ? __(
+ 'So far, there are no threats in your scan history for the current filter.',
'jetpack-protect'
- ),
- timeSinceLastScan
- ),
- {
- strong: ,
- }
- ) }
+ )
+ : createInterpolateElement(
+ sprintf(
+ // translators: placeholder is the amount of time since the last scan, i.e. "5 minutes ago".
+ __(
+ 'The last Protect scan ran %s and everything looked great.',
+ 'jetpack-protect'
+ ),
+ timeSinceLastScan
+ ),
+ {
+ strong: ,
+ }
+ ) }
);
diff --git a/projects/plugins/protect/src/js/components/threats-list/index.jsx b/projects/plugins/protect/src/js/components/threats-list/index.jsx
index cc0b21357e546..92f21af34c928 100644
--- a/projects/plugins/protect/src/js/components/threats-list/index.jsx
+++ b/projects/plugins/protect/src/js/components/threats-list/index.jsx
@@ -3,6 +3,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
import React, { useCallback, useState } from 'react';
import useProtectData from '../../hooks/use-protect-data';
+import useScanHistory from '../../hooks/use-scan-history';
import { STORE_ID } from '../../state/store';
import OnboardingPopover from '../onboarding-popover';
import EmptyList from './empty';
@@ -14,6 +15,7 @@ import useThreatsList from './use-threats-list';
const ThreatsList = () => {
const { hasRequiredPlan } = useProtectData();
+ const { viewingScanHistory, handleHistoryClick, allScanHistoryIsLoading } = useScanHistory();
const { item, list, selected, setSelected } = useThreatsList();
const fixableList = list.filter( obj => obj.fixable );
const [ isSm ] = useBreakpointMatch( 'sm' );
@@ -57,6 +59,13 @@ const ThreatsList = () => {
__( 'All %s threats', 'jetpack-protect' ),
list.length
);
+ case 'wordpress':
+ return sprintf(
+ /* translators: placeholder is the amount of WordPress threats found on the site. */
+ __( '%1$s WordPress %2$s', 'jetpack-protect' ),
+ list.length,
+ list.length === 1 ? 'threat' : 'threats'
+ );
case 'files':
return sprintf(
/* translators: placeholder is the amount of file threats found on the site. */
@@ -74,7 +83,7 @@ const ThreatsList = () => {
default:
return sprintf(
/* translators: Translates to Update to. %1$s: Name. %2$s: Fixed version */
- __( '%1$s %2$s in your %3$s %4$s', 'jetpack-protect' ),
+ __( '%1$s %2$s in %3$s %4$s', 'jetpack-protect' ),
list.length,
list.length === 1 ? 'threat' : 'threats',
item?.name,
@@ -100,7 +109,7 @@ const ThreatsList = () => {
<>
{ getTitle() }
- { hasRequiredPlan && (
+ { hasRequiredPlan && ! viewingScanHistory && (
<>
{ fixableList.length > 0 && (
<>
@@ -137,6 +146,14 @@ const ThreatsList = () => {
position={ isSm ? 'bottom left' : 'middle left' }
anchor={ dailyAndManualScansPopoverAnchor }
/>
+
>
) }
diff --git a/projects/plugins/protect/src/js/components/threats-list/navigation.jsx b/projects/plugins/protect/src/js/components/threats-list/navigation.jsx
index a4c37a27f022d..d460a8f86e870 100644
--- a/projects/plugins/protect/src/js/components/threats-list/navigation.jsx
+++ b/projects/plugins/protect/src/js/components/threats-list/navigation.jsx
@@ -23,6 +23,7 @@ const ThreatsNavigation = ( { selected, onSelect } ) => {
numDatabaseThreats,
hasRequiredPlan,
} = useProtectData();
+
const { recordEvent } = useAnalyticsTracks();
const [ isSmallOrLarge ] = useBreakpointMatch( 'lg', '<' );
diff --git a/projects/plugins/protect/src/js/components/threats-list/paid-list.jsx b/projects/plugins/protect/src/js/components/threats-list/paid-list.jsx
index 2a5a732b127fd..b7b0a8b6cff9d 100644
--- a/projects/plugins/protect/src/js/components/threats-list/paid-list.jsx
+++ b/projects/plugins/protect/src/js/components/threats-list/paid-list.jsx
@@ -4,6 +4,7 @@ import { createInterpolateElement } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import React, { useCallback } from 'react';
import useAnalyticsTracks from '../../hooks/use-analytics-tracks';
+import useScanHistory from '../../hooks/use-scan-history';
import { STORE_ID } from '../../state/store';
import DiffViewer from '../diff-viewer';
import MarkedLines from '../marked-lines';
@@ -15,7 +16,9 @@ const ThreatAccordionItem = ( {
description,
diff,
filename,
+ firstDetected,
fixedIn,
+ fixedOn,
icon,
fixable,
id,
@@ -27,6 +30,7 @@ const ThreatAccordionItem = ( {
severity,
} ) => {
const threatsAreFixing = useSelect( select => select( STORE_ID ).getThreatsAreFixing() );
+ const { viewingScanHistory } = useScanHistory();
const { setModal } = useDispatch( STORE_ID );
const { recordEvent } = useAnalyticsTracks();
@@ -66,6 +70,8 @@ const ThreatAccordionItem = ( {
icon={ icon }
fixable={ fixable }
severity={ severity }
+ firstDetected={ firstDetected }
+ fixedOn={ fixedOn }
onOpen={ useCallback( () => {
if ( ! [ 'core', 'plugin', 'theme', 'file', 'database' ].includes( type ) ) {
return;
@@ -115,14 +121,11 @@ const ThreatAccordionItem = ( {
) }
{ ! description && { learnMoreButton }
}
-
+ { ! viewingScanHistory && (
+
+ ) }
{ fixable && (