Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect: Separate scan results and history DataViews #40845

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4c95bfe
Init project branch
nateweller Nov 14, 2024
91ce2ed
Protect: Refactor AdminSectionHero (#40516)
nateweller Dec 9, 2024
35cd0cf
Restore history header
dkmyta Dec 10, 2024
5ad53b7
Pass status filter presets to consumer
dkmyta Dec 10, 2024
e21bb59
Restore early return
dkmyta Dec 10, 2024
50a5849
Add plan level restrictions
dkmyta Dec 10, 2024
d738a65
Init project branch
nateweller Nov 14, 2024
b93cfa2
Protect: Integrate ThreatsDataViews Component (#40076)
nateweller Dec 5, 2024
19bc943
Separate scan and history DataViews
dkmyta Jan 3, 2025
561ab57
Reapply history routes
dkmyta Jan 3, 2025
13ec8a0
Add filters
dkmyta Jan 3, 2025
996649a
Add toggle group control
dkmyta Jan 3, 2025
5a0871e
Add historic flag
dkmyta Jan 3, 2025
939263c
Update stories
dkmyta Jan 3, 2025
a34d4bd
Remove unneeded filter handling
dkmyta Jan 3, 2025
84a2ebc
Revert unnecessary threats data views updates
dkmyta Jan 3, 2025
1d3733f
Fix import
dkmyta Jan 3, 2025
61ee84d
Include fixer action as label in list view action dropdown
dkmyta Jan 3, 2025
a847325
Add field constants
dkmyta Jan 3, 2025
23b791f
Reorg
dkmyta Jan 3, 2025
9cd5469
Add initialFields prop, update active to current where applicable
dkmyta Jan 6, 2025
ad201c2
Init project branch
nateweller Nov 14, 2024
8960ec6
Fix exports and imports
dkmyta Jan 7, 2025
ec33096
Move default values to function params
nateweller Jan 12, 2025
5ccae12
Fix ts warning
nateweller Jan 12, 2025
dcb2887
minor adjustment to definition of initial filters
nateweller Jan 12, 2025
c8cd20e
Add tsc-expect-error to dummy arg for minification cases
nateweller Jan 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import {
wordpress as coreIcon,
} from '@wordpress/icons';

export const THREAT_STATUSES: { value: string; label: string; variant?: 'success' | 'warning' }[] =
[
{ value: 'current', label: __( 'Active', 'jetpack-components' ), variant: 'warning' },
{ value: 'fixed', label: __( 'Fixed', 'jetpack-components' ), variant: 'success' },
{ value: 'ignored', label: __( 'Ignored', 'jetpack-components' ) },
];
export const THREAT_STATUSES: { value: string; label: string; variant?: 'success' }[] = [
{ value: 'fixed', label: __( 'Fixed', 'jetpack-components' ), variant: 'success' },
{ value: 'ignored', label: __( 'Ignored', 'jetpack-components' ) },
];

export const THREAT_TYPES = [
{ value: 'plugins', label: __( 'Plugin', 'jetpack-components' ) },
Expand Down Expand Up @@ -45,6 +43,26 @@ export const THREAT_FIELD_FIRST_DETECTED = 'first-detected';
export const THREAT_FIELD_FIXED_ON = 'fixed-on';
export const THREAT_FIELD_AUTO_FIX = 'auto-fix';

export const CURRENT_TABLE_FIELDS = [
THREAT_FIELD_SEVERITY,
THREAT_FIELD_TYPE,
THREAT_FIELD_AUTO_FIX,
];

export const HISTORIC_TABLE_FIELDS = [
THREAT_FIELD_SEVERITY,
THREAT_FIELD_TYPE,
THREAT_FIELD_FIRST_DETECTED,
THREAT_FIELD_FIXED_ON,
];

export const LIST_FIELDS = [
THREAT_FIELD_SEVERITY,
THREAT_FIELD_TYPE,
THREAT_FIELD_EXTENSION,
THREAT_FIELD_SIGNATURE,
];

export const THREAT_ACTION_FIX = 'fix';
export const THREAT_ACTION_IGNORE = 'ignore';
export const THREAT_ACTION_UNIGNORE = 'unignore';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getThreatType, type Threat } from '@automattic/jetpack-scan';
import { getFixerAction, getThreatType, type Threat } from '@automattic/jetpack-scan';
import {
type Action,
type ActionButton,
Expand All @@ -19,6 +19,8 @@ import Badge from '../badge';
import ThreatFixerButton from '../threat-fixer-button';
import ThreatSeverityBadge from '../threat-severity-badge';
import {
CURRENT_TABLE_FIELDS,
LIST_FIELDS,
THREAT_ACTION_FIX,
THREAT_ACTION_IGNORE,
THREAT_ACTION_UNIGNORE,
Expand All @@ -40,52 +42,62 @@ import {
THREAT_TYPES,
} from './constants';
import styles from './styles.module.scss';
import ThreatsStatusToggleGroupControl from './threats-status-toggle-group-control';

export { HISTORIC_TABLE_FIELDS } from './constants';

/**
* DataViews component for displaying security threats.
*
* @param {object} props - Component props.
* @param {Array} props.data - Threats data.
* @param {Array} props.filters - Initial DataView filters.
* @param {Function} props.onChangeSelection - Callback function run when an item is selected.
* @param {Function} props.onFixThreats - Threat fix action callback.
* @param {Function} props.onIgnoreThreats - Threat ignore action callback.
* @param {Function} props.onUnignoreThreats - Threat unignore action callback.
* @param {Function} props.isThreatEligibleForFix - Function to determine if a threat is eligible for fixing.
* @param {Function} props.isThreatEligibleForIgnore - Function to determine if a threat is eligible for ignoring.
* @param {Function} props.isThreatEligibleForUnignore - Function to determine if a threat is eligible for unignoring.
* @param {object} props - Component props.
* @param {string} props.status - Flag to indicate if the threats are current or historic.
* @param {Array} props.data - Threats data.
* @param {Array} props.initialFilters - Initial DataView filters.
* @param {Array} props.initialFields - Initial DataView fields.
* @param {Function} props.onChangeSelection - Callback function run when an item is selected.
* @param {Function} props.onFixThreats - Threat fix action callback.
* @param {Function} props.onIgnoreThreats - Threat ignore action callback.
* @param {Function} props.onUnignoreThreats - Threat unignore action callback.
* @param {Function} props.isThreatEligibleForFix - Function to determine if a threat is eligible for fixing.
* @param {Function} props.isThreatEligibleForIgnore - Function to determine if a threat is eligible for ignoring.
* @param {Function} props.isThreatEligibleForUnignore - Function to determine if a threat is eligible for unignoring.
* @param {JSX.Element} props.header - Header component.
*
* @return {JSX.Element} The ThreatsDataViews component.
*/
export default function ThreatsDataViews( {
status = 'current',
data,
filters,
initialFields = CURRENT_TABLE_FIELDS,
initialFilters = [],
onChangeSelection,
isThreatEligibleForFix,
isThreatEligibleForIgnore,
isThreatEligibleForUnignore,
onFixThreats,
onIgnoreThreats,
onUnignoreThreats,
header,
}: {
status?: string;
data: Threat[];
filters?: Filter[];
initialFields?: string[];
initialFilters?: Filter[];
onChangeSelection?: ( selectedItemIds: string[] ) => void;
isThreatEligibleForFix?: ( threat: Threat ) => boolean;
isThreatEligibleForIgnore?: ( threat: Threat ) => boolean;
isThreatEligibleForUnignore?: ( threat: Threat ) => boolean;
onFixThreats?: ( threats: Threat[] ) => void;
onIgnoreThreats?: ActionButton< Threat >[ 'callback' ];
onUnignoreThreats?: ActionButton< Threat >[ 'callback' ];
header?: JSX.Element;
} ): JSX.Element {
const baseView = {
sort: {
field: 'severity',
direction: 'desc' as SortDirection,
},
search: '',
filters: filters || [],
filters: initialFilters,
page: 1,
perPage: 20,
};
Expand All @@ -100,19 +112,14 @@ export default function ThreatsDataViews( {
const defaultLayouts: SupportedLayouts = {
table: {
...baseView,
fields: [ THREAT_FIELD_SEVERITY, THREAT_FIELD_TYPE, THREAT_FIELD_AUTO_FIX ],
fields: initialFields,
titleField: THREAT_FIELD_TITLE,
descriptionField: THREAT_FIELD_DESCRIPTION,
showMedia: false,
},
list: {
...baseView,
fields: [
THREAT_FIELD_SEVERITY,
THREAT_FIELD_TYPE,
THREAT_FIELD_EXTENSION,
THREAT_FIELD_SIGNATURE,
],
fields: LIST_FIELDS,
titleField: THREAT_FIELD_TITLE,
mediaField: THREAT_FIELD_ICON,
showMedia: true,
Expand Down Expand Up @@ -238,28 +245,6 @@ export default function ThreatsDataViews( {
);
},
},
{
id: THREAT_FIELD_STATUS,
label: __( 'Status', 'jetpack-components' ),
elements: THREAT_STATUSES,
getValue( { item }: { item: Threat } ) {
if ( ! item.status ) {
return 'current';
}
return (
THREAT_STATUSES.find( ( { value } ) => value === item.status )?.value ?? item.status
);
},
render( { item }: { item: Threat } ) {
if ( item.status ) {
const status = THREAT_STATUSES.find( ( { value } ) => value === item.status );
if ( status ) {
return <Badge variant={ status?.variant }>{ status.label }</Badge>;
}
}
return <Badge variant="warning">{ __( 'Active', 'jetpack-components' ) }</Badge>;
},
},
{
id: THREAT_FIELD_TYPE,
label: __( 'Type', 'jetpack-components' ),
Expand Down Expand Up @@ -300,6 +285,35 @@ export default function ThreatsDataViews( {
return item.extension ? item.extension.slug : '';
},
},
...( 'historic' === status && dataFields.includes( 'status' )
? [
{
id: THREAT_FIELD_STATUS,
label: __( 'Status', 'jetpack-components' ),
elements: THREAT_STATUSES,
getValue( { item }: { item: Threat } ) {
if ( ! item.status ) {
return 'current';
}
return (
THREAT_STATUSES.find( ( { value } ) => value === item.status )?.value ??
item.status
);
},
render( { item }: { item: Threat } ) {
if ( item.status ) {
const threatStatus = THREAT_STATUSES.find(
( { value } ) => value === item.status
);
if ( threatStatus ) {
return <Badge variant={ threatStatus?.variant }>{ threatStatus.label }</Badge>;
}
}
return <Badge variant="warning">{ __( 'Current', 'jetpack-components' ) }</Badge>;
},
},
]
: [] ),
...( dataFields.includes( 'severity' )
? [
{
Expand Down Expand Up @@ -366,7 +380,7 @@ export default function ThreatsDataViews( {
},
]
: [] ),
...( dataFields.includes( 'fixable' )
...( 'historic' !== status && dataFields.includes( 'fixable' )
? [
{
id: THREAT_FIELD_AUTO_FIX,
Expand Down Expand Up @@ -398,7 +412,7 @@ export default function ThreatsDataViews( {
];

return result;
}, [ dataFields, plugins, themes, signatures, onFixThreats ] );
}, [ dataFields, plugins, themes, signatures, status, onFixThreats ] );

/**
* DataView actions - collection of operations that can be performed upon each record.
Expand All @@ -408,10 +422,12 @@ export default function ThreatsDataViews( {
const actions = useMemo( () => {
const result: Action< Threat >[] = [];

if ( dataFields.includes( 'fixable' ) ) {
if ( dataFields.includes( 'fixable' ) && view.type === 'list' ) {
result.push( {
id: THREAT_ACTION_FIX,
label: __( 'Auto-fix', 'jetpack-components' ),
label: items => {
return getFixerAction( items[ 0 ] );
},
isPrimary: true,
callback: onFixThreats,
isEligible( item ) {
Expand Down Expand Up @@ -466,6 +482,7 @@ export default function ThreatsDataViews( {

return result;
}, [
view.type,
dataFields,
onFixThreats,
onIgnoreThreats,
Expand Down Expand Up @@ -511,13 +528,7 @@ export default function ThreatsDataViews( {
onChangeView={ onChangeView }
paginationInfo={ paginationInfo }
view={ view }
header={
<ThreatsStatusToggleGroupControl
data={ data }
view={ view }
onChangeView={ onChangeView }
/>
}
header={ header }
/>
);
}
Loading
Loading