Skip to content

Commit

Permalink
ThreatsDataViews: ThreatModal integration (#40202)
Browse files Browse the repository at this point in the history
  • Loading branch information
dkmyta authored and nateweller committed Jan 14, 2025
1 parent cefda2b commit 9044e90
Show file tree
Hide file tree
Showing 26 changed files with 747 additions and 313 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Integrates ThreatModal in ThreatsDataViews
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { CONTACT_SUPPORT_URL } from '@automattic/jetpack-scan';
import { createInterpolateElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useMemo } from 'react';
import { Button } from '@automattic/jetpack-components';
import styles from './styles.module.scss';
import ThreatNotice from './threat-notice';

Expand All @@ -19,14 +22,28 @@ const FixerStateNotice = ( {
}: {
fixerState: { inProgress: boolean; error: boolean; stale: boolean };
} ) => {
const getInterpolatedContent = (): JSX.Element => {
return createInterpolateElement(
__( 'Please try again or <supportLink>contact support</supportLink>.', 'jetpack-components' ),
{
supportLink: <Button variant="link" isExternalLink={ true } href={ CONTACT_SUPPORT_URL } />,
}
);
};

const { status, title, content } = useMemo( () => {
if ( fixerState.error ) {
return {
status: 'error' as const,
title: __( 'An error occurred auto-fixing this threat', 'jetpack-components' ),
content: __(
'Jetpack encountered a filesystem error while attempting to auto-fix this threat. Please try again later or contact support.',
'jetpack-components'
content: (
<>
{ __(
'Jetpack encountered a filesystem error while attempting to auto-fix this threat.',
'jetpack-components'
) }{ ' ' }
{ getInterpolatedContent() }
</>
),
};
}
Expand All @@ -35,9 +52,14 @@ const FixerStateNotice = ( {
return {
status: 'error' as const,
title: __( 'The auto-fixer is taking longer than expected', 'jetpack-components' ),
content: __(
'Jetpack has been attempting to auto-fix this threat for too long, and something may have gone wrong. Please try again later or contact support.',
'jetpack-components'
content: (
<>
{ __(
'Jetpack has been attempting to auto-fix this threat for too long, and something may have gone wrong.',
'jetpack-components'
) }{ ' ' }
{ getInterpolatedContent() }
</>
),
};
}
Expand All @@ -55,7 +77,7 @@ const FixerStateNotice = ( {

return title ? (
<div className={ styles[ 'fixer-notice' ] }>
<ThreatNotice status={ status } title={ title } content={ content } />
<ThreatNotice status={ status } title={ title } content={ content } showActions={ false } />
</div>
) : null;
};
Expand Down
10 changes: 10 additions & 0 deletions projects/js-packages/components/components/threat-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import ThreatFixConfirmation from './threat-fix-confirmation';
interface ThreatModalContextType {
closeModal: () => void;
threat: Threat;
isSupportedEnvironment: boolean;
actionToConfirm: string | null;
handleUpgradeClick?: () => void;
userConnectionNeeded: boolean;
handleConnectUser: () => void;
Expand All @@ -27,6 +29,7 @@ export const ThreatModalContext = createContext< ThreatModalContextType | null >
*
* @param {object} props - The props.
* @param {object} props.threat - The threat.
* @param {boolean} props.isSupportedEnvironment - Whether the environment is supported.
* @param {boolean} props.isUserConnected - Whether the user is connected.
* @param {boolean} props.hasConnectedOwner - Whether the user has a connected owner.
* @param {boolean} props.userIsConnecting - Whether the user is connecting.
Expand All @@ -38,11 +41,13 @@ export const ThreatModalContext = createContext< ThreatModalContextType | null >
* @param {Function} props.handleFixThreatClick - The handleFixThreatClick function.
* @param {Function} props.handleIgnoreThreatClick - The handleIgnoreThreatClick function.
* @param {Function} props.handleUnignoreThreatClick - The handleUnignoreThreatClick function.
* @param {string} props.actionToConfirm - The action to confirm.
*
* @return {JSX.Element} The threat modal.
*/
export default function ThreatModal( {
threat,
isSupportedEnvironment,
isUserConnected,
hasConnectedOwner,
userIsConnecting,
Expand All @@ -54,9 +59,11 @@ export default function ThreatModal( {
handleFixThreatClick,
handleIgnoreThreatClick,
handleUnignoreThreatClick,
actionToConfirm,
...modalProps
}: {
threat: Threat;
isSupportedEnvironment: boolean;
isUserConnected: boolean;
hasConnectedOwner: boolean;
userIsConnecting: boolean;
Expand All @@ -68,6 +75,7 @@ export default function ThreatModal( {
handleFixThreatClick?: ( threats: Threat[] ) => void;
handleIgnoreThreatClick?: ( threats: Threat[] ) => void;
handleUnignoreThreatClick?: ( threats: Threat[] ) => void;
actionToConfirm: string | null;
} & React.ComponentProps< typeof Modal > ): JSX.Element {
const userConnectionNeeded = ! isUserConnected || ! hasConnectedOwner;
const siteCredentialsNeeded = ! credentials || credentials.length === 0;
Expand All @@ -88,6 +96,8 @@ export default function ThreatModal( {
value={ {
closeModal: modalProps.onRequestClose,
threat,
isSupportedEnvironment,
actionToConfirm,
handleUpgradeClick,
userConnectionNeeded,
handleConnectUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ const Base = args => {
const [ isOpen, setIsOpen ] = useState( false );
const onClick = useCallback( () => setIsOpen( true ), [] );
const onRequestClose = useCallback( () => setIsOpen( false ), [] );

return (
<div>
<Button onClick={ onClick }>Open Threat Modal</Button>
{ isOpen ? <ThreatModal { ...args } onRequestClose={ onRequestClose } /> : null }
{ isOpen ? (
<ThreatModal { ...args } onRequestClose={ onRequestClose } actionToConfirm={ 'all' } />
) : null }
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
display: flex;
flex-direction: column;
gap: calc( var( --spacing-base ) * 2 ); // 16px
}

.section .section__toggle {
text-decoration: none;

&:hover {
text-decoration: underline;
}

&__content {
display: flex;
gap: calc( var( --spacing-base ) / 2 ); // 4px
align-items: center;
.section__toggle {
text-decoration: none;

&:hover {
text-decoration: underline;
}

&__content {
display: flex;
gap: calc( var( --spacing-base ) / 2 ); // 4px
align-items: center;
}
}
}

Expand All @@ -43,6 +43,7 @@
.threat-actions {
display: flex;
justify-content: flex-end;
flex-wrap: wrap;
gap: calc( var( --spacing-base ) * 2 ); // 16px;
}
}
Expand All @@ -55,10 +56,6 @@
&__title {
display: flex;
gap: calc( var( --spacing-base ) / 2 ); // 4px

p {
font-weight: bold;
}
}

&__actions {
Expand All @@ -77,5 +74,4 @@ svg.spinner {
width: 20px;
margin-left: calc( var( --spacing-base ) / 2 ); // 4px;
margin-right: 6px;

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const ThreatActions = (): JSX.Element => {
const {
closeModal,
threat,
actionToConfirm,
handleFixThreatClick,
handleIgnoreThreatClick,
handleUnignoreThreatClick,
Expand Down Expand Up @@ -64,15 +65,17 @@ const ThreatActions = (): JSX.Element => {
) }
{ threat.status === 'current' && (
<>
<Button
isDestructive={ true }
variant="secondary"
onClick={ onIgnoreClick }
disabled={ disabled || ( fixerState.inProgress && ! fixerState.stale ) }
>
{ __( 'Ignore threat', 'jetpack-components' ) }
</Button>
{ threat.fixable && (
{ [ 'all', 'ignore' ].includes( actionToConfirm ) && (
<Button
isDestructive={ true }
variant="secondary"
onClick={ onIgnoreClick }
disabled={ disabled || ( fixerState.inProgress && ! fixerState.stale ) }
>
{ __( 'Ignore threat', 'jetpack-components' ) }
</Button>
) }
{ threat.fixable && [ 'all', 'fix' ].includes( actionToConfirm ) && (
<Button
isPrimary
disabled={ disabled || ( fixerState.inProgress && ! fixerState.stale ) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { __ } from '@wordpress/i18n';
import { useContext } from 'react';
import ContextualUpgradeTrigger from '../contextual-upgrade-trigger';
import ThreatActions from './threat-actions';
import ThreatFixDetails from './threat-fix-details';
import ThreatIgnoreDetails from './threat-ignore-details';
import ThreatNotice from './threat-notice';
import ThreatSummary from './threat-summary';
import ThreatTechnicalDetails from './threat-technical-details';
Expand All @@ -13,12 +15,14 @@ import { ThreatModalContext } from '.';
* @return {JSX.Element} The rendered fix confirmation.
*/
const ThreatFixConfirmation = () => {
const { userConnectionNeeded, siteCredentialsNeeded } = useContext( ThreatModalContext );
const { actionToConfirm, userConnectionNeeded, siteCredentialsNeeded, handleUpgradeClick } =
useContext( ThreatModalContext );
return (
<>
<ThreatSummary />
<ThreatTechnicalDetails />
<ThreatFixDetails />
{ [ 'all', 'fix' ].includes( actionToConfirm ) && <ThreatFixDetails /> }
{ [ 'all', 'ignore' ].includes( actionToConfirm ) && <ThreatIgnoreDetails /> }
{ siteCredentialsNeeded && userConnectionNeeded && (
<ThreatNotice
title={ 'Additional connections needed' }
Expand Down Expand Up @@ -46,6 +50,16 @@ const ThreatFixConfirmation = () => {
) }
/>
) }
{ handleUpgradeClick && (
<ContextualUpgradeTrigger
description={ __(
'Looking for advanced scan results and one-click fixes?',
'jetpack-components'
) }
cta={ __( 'Upgrade Jetpack now', 'jetpack-components' ) }
onClick={ handleUpgradeClick }
/>
) }
<ThreatActions />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { getFixerDescription } from '@automattic/jetpack-scan';
import { __, sprintf } from '@wordpress/i18n';
import React, { useMemo, useContext } from 'react';
import ContextualUpgradeTrigger from '../contextual-upgrade-trigger';
import Text from '../text';
import styles from './styles.module.scss';
import { ThreatModalContext } from '.';
Expand All @@ -12,7 +11,7 @@ import { ThreatModalContext } from '.';
* @return {JSX.Element | null} The rendered fix details or null if no fixable details are available.
*/
const ThreatFixDetails = (): JSX.Element => {
const { threat, handleUpgradeClick } = useContext( ThreatModalContext );
const { threat } = useContext( ThreatModalContext );

const title = useMemo( () => {
if ( threat.status === 'fixed' ) {
Expand Down Expand Up @@ -48,16 +47,6 @@ const ThreatFixDetails = (): JSX.Element => {
<div className={ styles.section }>
<Text variant="title-small">{ title }</Text>
<Text>{ fix }</Text>
{ handleUpgradeClick && (
<ContextualUpgradeTrigger
description={ __(
'Looking for advanced scan results and one-click fixes?',
'jetpack-components'
) }
cta={ __( 'Upgrade Jetpack now', 'jetpack-components' ) }
onClick={ handleUpgradeClick }
/>
) }
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { createInterpolateElement } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useContext } from 'react';
import { Text, Button, getRedirectUrl } from '@automattic/jetpack-components';
import styles from './styles.module.scss';
import { ThreatModalContext } from '.';

const ThreatIgnoreDetails = () => {
const { threat, isSupportedEnvironment } = useContext( ThreatModalContext );

if ( ! threat?.status || [ 'ignored', 'fixed' ].includes( threat.status ) ) {
return null;
}

const codeableURL = getRedirectUrl( 'jetpack-protect-codeable-referral' );

return (
<div className={ styles.section }>
<Text variant="title-small">
{ __( 'Do you really want to ignore this threat?', 'jetpack-components' ) }
</Text>
<Text>
{ __(
'By choosing to ignore this threat, you acknowledge that you have reviewed the detected code. You are accepting the risks of maintaining a potentially malicious or vulnerable file on your site.',
'jetpack-components'
) }{ ' ' }
{ isSupportedEnvironment &&
createInterpolateElement(
__(
'If you are unsure, please request an estimate with <codeableLink>Codeable</codeableLink>.',
'jetpack-components'
),
{
codeableLink: <Button variant="link" isExternalLink={ true } href={ codeableURL } />,
}
) }
</Text>
</div>
);
};

export default ThreatIgnoreDetails;
Loading

0 comments on commit 9044e90

Please sign in to comment.