diff --git a/projects/js-packages/components/changelog/add-components-threats-data-views-modal-integration b/projects/js-packages/components/changelog/add-components-threats-data-views-modal-integration
new file mode 100644
index 0000000000000..809bb1cd3a788
--- /dev/null
+++ b/projects/js-packages/components/changelog/add-components-threats-data-views-modal-integration
@@ -0,0 +1,4 @@
+Significance: minor
+Type: added
+
+Integrates ThreatModal in ThreatsDataViews
diff --git a/projects/js-packages/components/components/threat-modal/fixer-state-notice.tsx b/projects/js-packages/components/components/threat-modal/fixer-state-notice.tsx
index 8f130fba87421..861095cf0c363 100644
--- a/projects/js-packages/components/components/threat-modal/fixer-state-notice.tsx
+++ b/projects/js-packages/components/components/threat-modal/fixer-state-notice.tsx
@@ -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';
@@ -19,14 +22,28 @@ const FixerStateNotice = ( {
}: {
fixerState: { inProgress: boolean; error: boolean; stale: boolean };
} ) => {
+ const getInterpolatedContent = (): JSX.Element => {
+ return createInterpolateElement(
+ __( 'Please try again or contact support.', 'jetpack-components' ),
+ {
+ supportLink: ,
+ }
+ );
+ };
+
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() }
+ >
),
};
}
@@ -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() }
+ >
),
};
}
@@ -55,7 +77,7 @@ const FixerStateNotice = ( {
return title ? (
-
+
) : null;
};
diff --git a/projects/js-packages/components/components/threat-modal/index.tsx b/projects/js-packages/components/components/threat-modal/index.tsx
index aa0b1577559af..0d799df20a741 100644
--- a/projects/js-packages/components/components/threat-modal/index.tsx
+++ b/projects/js-packages/components/components/threat-modal/index.tsx
@@ -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;
@@ -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.
@@ -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,
@@ -54,9 +59,11 @@ export default function ThreatModal( {
handleFixThreatClick,
handleIgnoreThreatClick,
handleUnignoreThreatClick,
+ actionToConfirm,
...modalProps
}: {
threat: Threat;
+ isSupportedEnvironment: boolean;
isUserConnected: boolean;
hasConnectedOwner: boolean;
userIsConnecting: boolean;
@@ -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;
@@ -88,6 +96,8 @@ export default function ThreatModal( {
value={ {
closeModal: modalProps.onRequestClose,
threat,
+ isSupportedEnvironment,
+ actionToConfirm,
handleUpgradeClick,
userConnectionNeeded,
handleConnectUser,
diff --git a/projects/js-packages/components/components/threat-modal/stories/index.stories.tsx b/projects/js-packages/components/components/threat-modal/stories/index.stories.tsx
index eb799cb779b25..6018ce02f5dee 100644
--- a/projects/js-packages/components/components/threat-modal/stories/index.stories.tsx
+++ b/projects/js-packages/components/components/threat-modal/stories/index.stories.tsx
@@ -11,10 +11,13 @@ const Base = args => {
const [ isOpen, setIsOpen ] = useState( false );
const onClick = useCallback( () => setIsOpen( true ), [] );
const onRequestClose = useCallback( () => setIsOpen( false ), [] );
+
return (
- { isOpen ? : null }
+ { isOpen ? (
+
+ ) : null }
);
};
diff --git a/projects/js-packages/components/components/threat-modal/styles.module.scss b/projects/js-packages/components/components/threat-modal/styles.module.scss
index 1720d59b1f90c..a3cfb182c4eb3 100644
--- a/projects/js-packages/components/components/threat-modal/styles.module.scss
+++ b/projects/js-packages/components/components/threat-modal/styles.module.scss
@@ -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;
+ }
}
}
@@ -43,6 +43,7 @@
.threat-actions {
display: flex;
justify-content: flex-end;
+ flex-wrap: wrap;
gap: calc( var( --spacing-base ) * 2 ); // 16px;
}
}
@@ -55,10 +56,6 @@
&__title {
display: flex;
gap: calc( var( --spacing-base ) / 2 ); // 4px
-
- p {
- font-weight: bold;
- }
}
&__actions {
@@ -77,5 +74,4 @@ svg.spinner {
width: 20px;
margin-left: calc( var( --spacing-base ) / 2 ); // 4px;
margin-right: 6px;
-
}
\ No newline at end of file
diff --git a/projects/js-packages/components/components/threat-modal/threat-actions.tsx b/projects/js-packages/components/components/threat-modal/threat-actions.tsx
index e73f0450cc83f..f9feae4f694dc 100644
--- a/projects/js-packages/components/components/threat-modal/threat-actions.tsx
+++ b/projects/js-packages/components/components/threat-modal/threat-actions.tsx
@@ -15,6 +15,7 @@ const ThreatActions = (): JSX.Element => {
const {
closeModal,
threat,
+ actionToConfirm,
handleFixThreatClick,
handleIgnoreThreatClick,
handleUnignoreThreatClick,
@@ -64,15 +65,17 @@ const ThreatActions = (): JSX.Element => {
) }
{ threat.status === 'current' && (
<>
-
- { threat.fixable && (
+ { [ 'all', 'ignore' ].includes( actionToConfirm ) && (
+
+ ) }
+ { threat.fixable && [ 'all', 'fix' ].includes( actionToConfirm ) && (