-
Notifications
You must be signed in to change notification settings - Fork 800
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ThreatsDataViews: Add ToggleGroupControl (#39901)
* Components: add hoverShow prop to IconTooltip * changelog * Add ThreatsDataView changelog * Add ToggleGroupControl filters to ThreatsDataView * Components: add hoverShow prop to IconTooltip * changelog * Add ThreatsDataView changelog Use inline button for primary fixer action * Fix rebase issues * Fixes, updates * Improve type checks * Components: add hoverShow prop to IconTooltip * changelog * Add ThreatsDataView * Story fixes * Update toggle text * Fix story data * changelog * Fix changelog entry * Fix types * Update approach to counting threats * Fix tests * Update lock file * Revert lock file changes * Set __nextHasNoMarginBottom to avoid deprecation warning * Move toggle to dedicated file * Add default filters to stories * Wrap experimental component rendering in try/catch * Update projects/js-packages/components/components/threats-data-views/index.tsx Co-authored-by: Nate Weller <[email protected]> * Update projects/js-packages/components/components/threats-data-views/index.tsx Co-authored-by: Nate Weller <[email protected]> * Update projects/js-packages/components/components/threats-data-views/index.tsx Co-authored-by: Nate Weller <[email protected]> * Update projects/js-packages/components/components/threats-data-views/threats-status-toggle-group-control.tsx Co-authored-by: Nate Weller <[email protected]> * Fix lint errors --------- Co-authored-by: Nate Weller <[email protected]> Co-authored-by: Nate Weller <[email protected]>
- Loading branch information
1 parent
7c0b2a8
commit e9b0e4f
Showing
6 changed files
with
192 additions
and
12 deletions.
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
...cts/js-packages/components/changelog/add-component-threats-data-view-toggle-group-control
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
Significance: minor | ||
Type: changed | ||
|
||
Add ToggleGroupControl to ThreatsDataViews for easily toggling between Active and Historical threats |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,7 +42,6 @@ const data = [ | |
type: 'plugin' as const, | ||
}, | ||
fixedIn: '3.2.4', | ||
status: 'current' as const, | ||
}, | ||
]; | ||
|
||
|
160 changes: 160 additions & 0 deletions
160
...packages/components/components/threats-data-views/threats-status-toggle-group-control.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import { type Threat, type ThreatStatus } from '@automattic/jetpack-scan'; | ||
import { | ||
__experimentalToggleGroupControl as ToggleGroupControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis | ||
__experimentalToggleGroupControlOption as ToggleGroupControlOption, // eslint-disable-line @wordpress/no-unsafe-wp-apis | ||
} from '@wordpress/components'; | ||
import { type View } from '@wordpress/dataviews'; | ||
import { useMemo, useCallback } from '@wordpress/element'; | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import styles from './styles.module.scss'; | ||
|
||
/** | ||
* ToggleGroupControl component for filtering threats by status. | ||
* @param {object} props - Component props. | ||
* @param { Threat[]} props.data - Threats data. | ||
* @param { View } props.view - The current view. | ||
* @param { Function } props.onChangeView - Callback function to handle view changes. | ||
* @return {JSX.Element|null} The component or null. | ||
*/ | ||
export default function ThreatsStatusToggleGroupControl( { | ||
data, | ||
view, | ||
onChangeView, | ||
}: { | ||
data: Threat[]; | ||
view: View; | ||
onChangeView: ( newView: View ) => void; | ||
} ): JSX.Element { | ||
/** | ||
* Compute values from the provided threats data. | ||
* | ||
* @member {number} activeThreatsCount - Count of active threats. | ||
* @member {number} historicThreatsCount - Count of historic threats. | ||
*/ | ||
const { | ||
activeThreatsCount, | ||
historicThreatsCount, | ||
}: { | ||
activeThreatsCount: number; | ||
historicThreatsCount: number; | ||
} = useMemo( () => { | ||
return data.reduce( | ||
( acc, threat ) => { | ||
if ( threat.status ) { | ||
if ( threat.status === 'current' ) { | ||
acc.activeThreatsCount++; | ||
} else { | ||
acc.historicThreatsCount++; | ||
} | ||
} | ||
return acc; | ||
}, | ||
{ | ||
activeThreatsCount: 0, | ||
historicThreatsCount: 0, | ||
} | ||
); | ||
}, [ data ] ); | ||
|
||
/** | ||
* Callback function to handle the status change filter. | ||
* | ||
* @param {string} newStatus - The new status filter value. | ||
*/ | ||
const onStatusFilterChange = useCallback( | ||
( newStatus: string ) => { | ||
const updatedFilters = view.filters.filter( filter => filter.field !== 'status' ); | ||
|
||
if ( newStatus === 'active' ) { | ||
updatedFilters.push( { | ||
field: 'status', | ||
operator: 'isAny', | ||
value: [ 'current' ], | ||
} ); | ||
} else if ( newStatus === 'historic' ) { | ||
updatedFilters.push( { | ||
field: 'status', | ||
operator: 'isAny', | ||
value: [ 'fixed', 'ignored' ], | ||
} ); | ||
} | ||
|
||
onChangeView( { | ||
...view, | ||
filters: updatedFilters, | ||
} ); | ||
}, | ||
[ view, onChangeView ] | ||
); | ||
|
||
/** | ||
* Memoized function to determine if a status filter is selected. | ||
* | ||
* @param {Array} threatStatuses - List of threat statuses. | ||
*/ | ||
const isStatusFilterSelected = useMemo( | ||
() => ( threatStatuses: ThreatStatus[] ) => | ||
view.filters.some( | ||
filter => | ||
filter.field === 'status' && | ||
Array.isArray( filter.value ) && | ||
filter.value.length === threatStatuses.length && | ||
threatStatuses.every( threatStatus => filter.value.includes( threatStatus ) ) | ||
), | ||
[ view.filters ] | ||
); | ||
|
||
const selectedValue = useMemo( () => { | ||
if ( isStatusFilterSelected( [ 'current' ] ) ) { | ||
return 'active' as const; | ||
} | ||
if ( isStatusFilterSelected( [ 'fixed', 'ignored' ] ) ) { | ||
return 'historic' as const; | ||
} | ||
return '' as const; | ||
}, [ isStatusFilterSelected ] ); | ||
|
||
if ( ! ( activeThreatsCount + historicThreatsCount ) ) { | ||
return null; | ||
} | ||
|
||
try { | ||
return ( | ||
<ToggleGroupControl | ||
className={ styles[ 'toggle-group-control' ] } | ||
value={ selectedValue } | ||
onChange={ onStatusFilterChange } | ||
__nextHasNoMarginBottom | ||
> | ||
<ToggleGroupControlOption | ||
value="active" | ||
label={ | ||
<span className={ styles[ 'toggle-group-control__option' ] }> | ||
{ sprintf( | ||
/* translators: %d: number of active threats */ __( | ||
'Active threats (%d)', | ||
'jetpack' | ||
), | ||
activeThreatsCount | ||
) } | ||
</span> | ||
} | ||
/> | ||
<ToggleGroupControlOption | ||
value="historic" | ||
label={ | ||
<span className={ styles[ 'toggle-group-control__option' ] }> | ||
{ sprintf( | ||
/* translators: %d: number of historic threats */ | ||
__( 'History (%d)', 'jetpack' ), | ||
historicThreatsCount | ||
) } | ||
</span> | ||
} | ||
/> | ||
</ToggleGroupControl> | ||
); | ||
} catch ( error ) { | ||
return null; | ||
} | ||
} |