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: Show loading indicator as status icon when scan in progress #40624

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
22bffcb
Init project branch
nateweller Nov 14, 2024
49bf778
Protect: Add Go to Cloud and Scan now button to Protect primary heade…
dkmyta Nov 14, 2024
54a6afd
Protect: Update Scan and History headers (#40058)
dkmyta Nov 14, 2024
ba4c154
Protect: de-emphasize cloud link by using link variant (#40211)
nateweller Nov 18, 2024
d8d87a3
Protect: add ShieldIcon component
nateweller Nov 30, 2024
7c61683
Protect: Add ShieldIcon Component (#40402)
nateweller Dec 5, 2024
9e31e6c
Protect: Integrate ThreatsDataViews Component (#40076)
nateweller Dec 5, 2024
47b04da
Components: Add ScanReport (#40419)
dkmyta Dec 5, 2024
490446f
Fix type errors
nateweller Dec 6, 2024
ee76878
Protect: Refactor AdminSectionHero (#40516)
nateweller Dec 9, 2024
ca05e6d
Protect: Update Scan History extension types (#40548)
dkmyta Dec 10, 2024
3c4992e
Protect: Add Home page (#40317)
dkmyta Dec 10, 2024
a58499b
Protect: Integrate ScanReport (#40420)
dkmyta Dec 11, 2024
b5900e7
Fix duplicate imports
nateweller Dec 15, 2024
3afff25
ScanReport: Fix defaultLayout (#40603)
dkmyta Dec 15, 2024
69a281a
Update onboarding popover placement (#40550)
dkmyta Dec 15, 2024
b04eeff
Init project branch
nateweller Nov 14, 2024
eba4892
Protect: minor enhancements to scan report data
nateweller Dec 15, 2024
d16a2a6
Remove file extension name property
nateweller Dec 17, 2024
4b339dc
Remove unused import
nateweller Dec 17, 2024
2f44be8
Init project branch
nateweller Nov 14, 2024
ee50c09
Scan Report: add min width to status icon to center with column label
nateweller Dec 15, 2024
e0ab4db
Init project branch
nateweller Nov 14, 2024
3136c28
Apply max width to hero content
nateweller Dec 15, 2024
c3f5cf4
Init project branch
nateweller Nov 14, 2024
a529dba
Protect: only show Scan Report when scan is in progress or has result…
nateweller Dec 15, 2024
0096404
Init project branch
nateweller Nov 14, 2024
afd7886
Protect: only show Scan Report when scan is in progress or has result…
nateweller Dec 15, 2024
12484d6
Protect: only show Threats DataViews when scan is in progress or has …
nateweller Dec 15, 2024
48eecea
Init project branch
nateweller Nov 14, 2024
e6fa532
Protect: only show Threats DataViews when scan is in progress or has …
nateweller Dec 15, 2024
21039d2
Protect: use error variant for threats in home hero, use solid varian…
nateweller Dec 15, 2024
2c07ff5
Fix merge conflict
nateweller Dec 17, 2024
243b439
Use outline variant for shield icon in scan error stat card
nateweller Dec 17, 2024
a81ba4d
Init project branch
nateweller Nov 14, 2024
9a6e7ee
Protect: use flex gap to space home page stat cards
nateweller Dec 15, 2024
a7f3747
Init project branch
nateweller Nov 14, 2024
d860f37
Protect: show loading indicator in status column when scan is in prog…
nateweller Dec 15, 2024
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';
246 changes: 246 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,246 @@
import { type ScanReportExtension } from '@automattic/jetpack-scan';
import { Spinner, 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.
* @param {boolean} props.scanInProgress - Whether a scan is in progress.
*
* @return {JSX.Element} The ScanReport component.
*/
export default function ScanReport( {
dataSource,
data,
onChangeSelection,
scanInProgress = false,
} ): 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 ],
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' ),
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' | 'warning' | '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 = 'warning';
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 }>
{ scanInProgress ? (
<Spinner />
) : (
<ShieldIcon variant={ variant } height={ iconHeight } />
) }
</div>
</Tooltip>
);
},
},
{
id: FIELD_TYPE,
label: __( 'Type', 'jetpack-components' ),
elements: TYPES,
},
{
id: FIELD_NAME,
label: __( 'Name', 'jetpack-components' ),
enableGlobalSearch: true,
getValue( { item }: { item: ScanReportExtension } ) {
return item.name ? item.name : '';
},
},
{
id: FIELD_VERSION,
label: __( 'Version', 'jetpack-components' ),
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.type, dataSource, scanInProgress ] );

/**
* 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