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

Open
wants to merge 58 commits into
base: add/protect/core
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
4dd60b7
Init project branch
nateweller Nov 14, 2024
ff92d88
Protect: Add Go to Cloud and Scan now button to Protect primary heade…
dkmyta Nov 14, 2024
39e4094
Protect: Update Scan and History headers (#40058)
dkmyta Nov 14, 2024
9fec011
Protect: de-emphasize cloud link by using link variant (#40211)
nateweller Nov 18, 2024
af172c9
Protect: add ShieldIcon component
nateweller Nov 30, 2024
00283bc
Protect: Add ShieldIcon Component (#40402)
nateweller Dec 5, 2024
f580ace
Protect: Integrate ThreatsDataViews Component (#40076)
nateweller Dec 5, 2024
c384d69
Components: Add ScanReport (#40419)
dkmyta Dec 5, 2024
68569f2
Fix type errors
nateweller Dec 6, 2024
91ee20a
Protect: Refactor AdminSectionHero (#40516)
nateweller Dec 9, 2024
5892e03
Restore history header
dkmyta Dec 10, 2024
ffb3ab0
Pass status filter presets to consumer
dkmyta Dec 10, 2024
3ad2ee8
Restore early return
dkmyta Dec 10, 2024
7ca9b41
Add plan level restrictions
dkmyta Dec 10, 2024
609a47e
Init project branch
nateweller Nov 14, 2024
43b9566
Protect: Add Go to Cloud and Scan now button to Protect primary heade…
dkmyta Nov 14, 2024
0f9d355
Protect: Update Scan and History headers (#40058)
dkmyta Nov 14, 2024
d7ec48a
Protect: de-emphasize cloud link by using link variant (#40211)
nateweller Nov 18, 2024
3195cb3
Protect: add ShieldIcon component
nateweller Nov 30, 2024
1b4eca4
Protect: Add ShieldIcon Component (#40402)
nateweller Dec 5, 2024
3d878c7
Protect: Integrate ThreatsDataViews Component (#40076)
nateweller Dec 5, 2024
e5d5b04
Components: Add ScanReport (#40419)
dkmyta Dec 5, 2024
7ef8809
Fix type errors
nateweller Dec 6, 2024
55a8d4f
Protect: Refactor AdminSectionHero (#40516)
nateweller Dec 9, 2024
f33e209
Protect: Update Scan History extension types (#40548)
dkmyta Dec 10, 2024
94c9c9a
Protect: Add Home page (#40317)
dkmyta Dec 10, 2024
88960de
Protect: Integrate ScanReport (#40420)
dkmyta Dec 11, 2024
62314b0
Fix duplicate imports
nateweller Dec 15, 2024
a0e7243
ScanReport: Fix defaultLayout (#40603)
dkmyta Dec 15, 2024
113e002
Update onboarding popover placement (#40550)
dkmyta Dec 15, 2024
338e67f
Protect Meets Core: Home Page Scan Report Data Adjustments (#40616)
nateweller Dec 18, 2024
484ce7c
Scan Report: Align Status Icon (#40617)
nateweller Dec 18, 2024
bbc2d56
Apply max width to hero content (#40618)
nateweller Dec 18, 2024
f3874ab
Protect: Hide Scan Report When No Data (#40619)
nateweller Dec 18, 2024
32bcff9
Protect: Hide Threats Report When No Data (#40620)
nateweller Dec 18, 2024
97f5c59
Protect: Update Threat Icons (#40621)
nateweller Dec 18, 2024
898ae2c
Protect: fix home page stat card spacing (#40623)
nateweller Dec 18, 2024
f2587f7
Fix ESLint issue
nateweller Jan 1, 2025
1db1e6c
ScanReport: Disable hiding relevant fields (#40602)
dkmyta Jan 2, 2025
8bd4c21
Rebase
dkmyta Jan 2, 2025
3dae6d4
Separate scan and history DataViews
dkmyta Jan 3, 2025
fbfe605
Reapply history routes
dkmyta Jan 3, 2025
f2bcbe7
Add filters
dkmyta Jan 3, 2025
4afa6fc
Add toggle group control
dkmyta Jan 3, 2025
6db0f6f
Add historic flag
dkmyta Jan 3, 2025
cdac95f
Update stories
dkmyta Jan 3, 2025
010b2c1
Remove unneeded filter handling
dkmyta Jan 3, 2025
c86dc12
Revert unnecessary threats data views updates
dkmyta Jan 3, 2025
d86c933
Fix import
dkmyta Jan 3, 2025
407e4ba
Add size prop
dkmyta Jan 3, 2025
f672f0a
Use error variant (#40832)
dkmyta Jan 3, 2025
1c72079
Merge branch 'add/protect/core' into restore/protect/history-admin-se…
dkmyta Jan 3, 2025
856479c
Rebase
dkmyta Jan 3, 2025
137f2a8
Include fixer action as label in list view action dropdown
dkmyta Jan 3, 2025
1c24e44
Add field constants
dkmyta Jan 3, 2025
8038593
Reorg
dkmyta Jan 3, 2025
4068ba6
Add initialFields prop, update active to current where applicable
dkmyta Jan 6, 2025
19b7834
Rebase, fix conflicts
dkmyta Jan 6, 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
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Stat Card: add hideValue prop
4 changes: 4 additions & 0 deletions projects/js-packages/components/changelog/add-shield-icon
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add ShieldIcon component
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Adds ScanReport component
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { __ } from '@wordpress/i18n';
import {
code as fileIcon,
color as themeIcon,
plugins as pluginIcon,
shield as shieldIcon,
wordpress as coreIcon,
} from '@wordpress/icons';

export const STATUS_TYPES = [
{ value: 'checked', label: __( 'Checked', 'jetpack-components' ) },
{ value: 'unchecked', label: __( 'Unchecked', 'jetpack-components' ) },
{ value: 'threat', label: __( 'Threat', 'jetpack-components' ) },
];

export const TYPES = [
{ value: 'core', label: __( 'WordPress', 'jetpack-components' ) },
{ value: 'plugins', label: __( 'Plugin', 'jetpack-components' ) },
{ value: 'themes', label: __( 'Theme', 'jetpack-components' ) },
{ value: 'files', label: __( 'Files', 'jetpack-components' ) },
];

export const ICONS = {
plugins: pluginIcon,
themes: themeIcon,
core: coreIcon,
files: fileIcon,
default: shieldIcon,
};

export const FIELD_ICON = 'icon';
export const FIELD_TYPE = 'type';
export const FIELD_NAME = 'name';
export const FIELD_STATUS = 'status';
export const FIELD_UPDATE = 'update';
export const FIELD_VERSION = 'version';
240 changes: 240 additions & 0 deletions projects/js-packages/components/components/scan-report/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import { type ScanReportExtension } from '@automattic/jetpack-scan';
import { Tooltip } from '@wordpress/components';
import {
type SupportedLayouts,
type View,
type Field,
DataViews,
filterSortAndPaginate,
} from '@wordpress/dataviews';
import { __, _n } from '@wordpress/i18n';
import { Icon } from '@wordpress/icons';
import { useCallback, useMemo, useState } from 'react';
import ShieldIcon from '../shield-icon';
import {
FIELD_NAME,
FIELD_VERSION,
FIELD_ICON,
FIELD_STATUS,
FIELD_TYPE,
STATUS_TYPES,
TYPES,
ICONS,
} from './constants';
import styles from './styles.module.scss';

/**
* DataViews component for displaying a scan report.
*
* @param {object} props - Component props.
* @param {string} props.dataSource - Data source.
* @param {Array} props.data - Scan report data.
* @param {Function} props.onChangeSelection - Callback function run when an item is selected.
*
* @return {JSX.Element} The ScanReport component.
*/
export default function ScanReport( { dataSource, data, onChangeSelection } ): JSX.Element {
const baseView = {
search: '',
filters: [],
page: 1,
perPage: 20,
};

/**
* DataView default layouts.
*
* This property provides layout information about the view types that are active. If empty, enables all layout types (see “Layout Types”) with empty layout data.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#defaultlayouts-record-string-view
*/
const defaultLayouts: SupportedLayouts = {
table: {
...baseView,
fields: [ FIELD_TYPE, FIELD_NAME, FIELD_VERSION ],
titleField: FIELD_STATUS,
showMedia: false,
},
list: {
...baseView,
fields: [ FIELD_STATUS, FIELD_VERSION, FIELD_TYPE ],
titleField: FIELD_NAME,
mediaField: FIELD_ICON,
showMedia: true,
},
};

/**
* DataView view object - configures how the dataset is visible to the user.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#view-object
*/
const [ view, setView ] = useState< View >( {
type: 'table',
...defaultLayouts.table,
} );

/**
* DataView fields - describes the visible items for each record in the dataset.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#fields-object
*/
const fields = useMemo( () => {
const iconHeight = 20;
const result: Field< ScanReportExtension >[] = [
{
id: FIELD_STATUS,
elements: STATUS_TYPES,
label: __( 'Status', 'jetpack-components' ),
enableHiding: false,
getValue( { item } ) {
if ( item.checked ) {
if ( item.threats.length > 0 ) {
return 'threat';
}
return 'checked';
}
return 'unchecked';
},
render( { item }: { item: ScanReportExtension } ) {
const scanApi = 'scan_api' === dataSource;
let variant: 'info' | 'error' | 'success' = 'info';
let text = __(
'This item was added to your site after the most recent scan. We will check for threats during the next scheduled one.',
'jetpack-components'
);

if ( item.checked ) {
if ( item.threats.length > 0 ) {
variant = 'error';
text = _n(
'Vulnerability detected.',
'Vulnerabilities detected.',
item.threats.length,
'jetpack-components'
);

if ( scanApi ) {
text = _n(
'Threat detected.',
'Threats detected.',
item.threats.length,
'jetpack-components'
);
}
} else {
variant = 'success';
text = __(
'No known vulnerabilities found that affect this version.',
'jetpack-components'
);

if ( scanApi ) {
text = __(
'No known threats found that affect this version.',
'jetpack-components'
);
}
}
}

return (
<Tooltip className={ styles.tooltip } text={ text }>
<div className={ styles.icon }>
<ShieldIcon variant={ variant } height={ iconHeight } />
</div>
</Tooltip>
);
},
},
{
id: FIELD_TYPE,
label: __( 'Type', 'jetpack-components' ),
elements: TYPES,
enableHiding: false,
},
{
id: FIELD_NAME,
label: __( 'Name', 'jetpack-components' ),
enableHiding: false,
enableGlobalSearch: true,
getValue( { item }: { item: ScanReportExtension } ) {
return item.name ? item.name : '';
},
},
{
id: FIELD_VERSION,
label: __( 'Version', 'jetpack-components' ),
enableHiding: false,
enableSorting: false,
enableGlobalSearch: true,
getValue( { item }: { item: ScanReportExtension } ) {
return item.version ? item.version : '';
},
},
...( view.type === 'list'
? [
{
id: FIELD_ICON,
label: __( 'Icon', 'jetpack-components' ),
enableSorting: false,
enableHiding: false,
getValue( { item }: { item: ScanReportExtension } ) {
return ICONS[ item.type ] || '';
},
render( { item }: { item: ScanReportExtension } ) {
return (
<div className={ styles.threat__media }>
<Icon icon={ ICONS[ item.type ] } />
</div>
);
},
},
]
: [] ),
];

return result;
}, [ view, dataSource ] );

/**
* Apply the view settings (i.e. filters, sorting, pagination) to the dataset.
*
* @see https://github.com/WordPress/gutenberg/blob/trunk/packages/dataviews/src/filter-and-sort-data-view.ts
*/
const { data: processedData, paginationInfo } = useMemo( () => {
return filterSortAndPaginate( data, view, fields );
}, [ data, view, fields ] );

/**
* Callback function to update the view state.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#onchangeview-function
*/
const onChangeView = useCallback( ( newView: View ) => {
setView( newView );
}, [] );

/**
* DataView getItemId function - returns the unique ID for each record in the dataset.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#getitemid-function
*/
const getItemId = useCallback(
( item: ScanReportExtension ) => `${ item.type }_${ item.slug }_${ item.version }`,
[]
);

return (
<DataViews
data={ processedData }
defaultLayouts={ defaultLayouts }
fields={ fields }
getItemId={ getItemId }
onChangeSelection={ onChangeSelection }
onChangeView={ onChangeView }
paginationInfo={ paginationInfo }
view={ view }
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import ScanReport from '..';

export default {
title: 'JS Packages/Components/Scan Report',
component: ScanReport,
parameters: {
backgrounds: {
default: 'light',
values: [ { name: 'light', value: 'white' } ],
},
},
decorators: [
Story => (
<div style={ { maxWidth: '100%', backgroundColor: 'white' } }>
<Story />
</div>
),
],
};

export const Default = args => <ScanReport { ...args } />;
Default.args = {
dataSource: 'scan_api',
data: [
{
id: 1,
name: 'WordPress',
slug: null,
version: '6.7.1',
threats: [],
checked: true,
type: 'core',
},
{
id: 2,
name: 'Jetpack',
slug: 'jetpack/jetpack.php',
version: '14.1-a.7',
threats: [],
checked: false,
type: 'plugins',
},
{
id: 3,
name: 'Twenty Fifteen',
slug: 'twentyfifteen',
version: '1.1',
threats: [
{
id: 198352527,
signature: 'Vulnerable.WP.Extension',
description: 'Vulnerable WordPress extension',
severity: 3,
},
],
checked: true,
type: 'themes',
},
{
id: 4,
threats: [
{
id: 198352406,
signature: 'EICAR_AV_Test_Suspicious',
title: 'Malicious code found in file: jptt_eicar.php',
severity: 1,
},
{
id: 198352407,
signature: 'EICAR_AV_Test_Suspicious',
title: 'Malicious code found in file: jptt_eicar.php',
severity: 1,
},
],
checked: true,
type: 'files',
},
],
};
Loading
Loading