@automattic/jetpack-components 0.58.0 → 0.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ import { type Threat, type ThreatStatus } from '@automattic/jetpack-scan';
2
+ import {
3
+ __experimentalToggleGroupControl as ToggleGroupControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis
4
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption, // eslint-disable-line @wordpress/no-unsafe-wp-apis
5
+ } from '@wordpress/components';
6
+ import { type View } from '@wordpress/dataviews';
7
+ import { useMemo, useCallback } from '@wordpress/element';
8
+ import { __, sprintf } from '@wordpress/i18n';
9
+ import styles from './styles.module.scss';
10
+
11
+ /**
12
+ * ToggleGroupControl component for filtering threats by status.
13
+ * @param {object} props - Component props.
14
+ * @param { Threat[]} props.data - Threats data.
15
+ * @param { View } props.view - The current view.
16
+ * @param { Function } props.onChangeView - Callback function to handle view changes.
17
+ * @return {JSX.Element|null} The component or null.
18
+ */
19
+ export default function ThreatsStatusToggleGroupControl( {
20
+ data,
21
+ view,
22
+ onChangeView,
23
+ }: {
24
+ data: Threat[];
25
+ view: View;
26
+ onChangeView: ( newView: View ) => void;
27
+ } ): JSX.Element {
28
+ /**
29
+ * Compute values from the provided threats data.
30
+ *
31
+ * @member {number} activeThreatsCount - Count of active threats.
32
+ * @member {number} historicThreatsCount - Count of historic threats.
33
+ */
34
+ const {
35
+ activeThreatsCount,
36
+ historicThreatsCount,
37
+ }: {
38
+ activeThreatsCount: number;
39
+ historicThreatsCount: number;
40
+ } = useMemo( () => {
41
+ return data.reduce(
42
+ ( acc, threat ) => {
43
+ if ( threat.status ) {
44
+ if ( threat.status === 'current' ) {
45
+ acc.activeThreatsCount++;
46
+ } else {
47
+ acc.historicThreatsCount++;
48
+ }
49
+ }
50
+ return acc;
51
+ },
52
+ {
53
+ activeThreatsCount: 0,
54
+ historicThreatsCount: 0,
55
+ }
56
+ );
57
+ }, [ data ] );
58
+
59
+ /**
60
+ * Callback function to handle the status change filter.
61
+ *
62
+ * @param {string} newStatus - The new status filter value.
63
+ */
64
+ const onStatusFilterChange = useCallback(
65
+ ( newStatus: string ) => {
66
+ const updatedFilters = view.filters.filter( filter => filter.field !== 'status' );
67
+
68
+ if ( newStatus === 'active' ) {
69
+ updatedFilters.push( {
70
+ field: 'status',
71
+ operator: 'isAny',
72
+ value: [ 'current' ],
73
+ } );
74
+ } else if ( newStatus === 'historic' ) {
75
+ updatedFilters.push( {
76
+ field: 'status',
77
+ operator: 'isAny',
78
+ value: [ 'fixed', 'ignored' ],
79
+ } );
80
+ }
81
+
82
+ onChangeView( {
83
+ ...view,
84
+ filters: updatedFilters,
85
+ } );
86
+ },
87
+ [ view, onChangeView ]
88
+ );
89
+
90
+ /**
91
+ * Memoized function to determine if a status filter is selected.
92
+ *
93
+ * @param {Array} threatStatuses - List of threat statuses.
94
+ */
95
+ const isStatusFilterSelected = useMemo(
96
+ () => ( threatStatuses: ThreatStatus[] ) =>
97
+ view.filters.some(
98
+ filter =>
99
+ filter.field === 'status' &&
100
+ Array.isArray( filter.value ) &&
101
+ filter.value.length === threatStatuses.length &&
102
+ threatStatuses.every( threatStatus => filter.value.includes( threatStatus ) )
103
+ ),
104
+ [ view.filters ]
105
+ );
106
+
107
+ const selectedValue = useMemo( () => {
108
+ if ( isStatusFilterSelected( [ 'current' ] ) ) {
109
+ return 'active' as const;
110
+ }
111
+ if ( isStatusFilterSelected( [ 'fixed', 'ignored' ] ) ) {
112
+ return 'historic' as const;
113
+ }
114
+ return '' as const;
115
+ }, [ isStatusFilterSelected ] );
116
+
117
+ if ( ! ( activeThreatsCount + historicThreatsCount ) ) {
118
+ return null;
119
+ }
120
+
121
+ try {
122
+ return (
123
+ <ToggleGroupControl
124
+ className={ styles[ 'toggle-group-control' ] }
125
+ value={ selectedValue }
126
+ onChange={ onStatusFilterChange }
127
+ __nextHasNoMarginBottom
128
+ >
129
+ <ToggleGroupControlOption
130
+ value="active"
131
+ label={
132
+ <span className={ styles[ 'toggle-group-control__option' ] }>
133
+ { sprintf(
134
+ /* translators: %d: number of active threats */ __(
135
+ 'Active threats (%d)',
136
+ 'jetpack'
137
+ ),
138
+ activeThreatsCount
139
+ ) }
140
+ </span>
141
+ }
142
+ />
143
+ <ToggleGroupControlOption
144
+ value="historic"
145
+ label={
146
+ <span className={ styles[ 'toggle-group-control__option' ] }>
147
+ { sprintf(
148
+ /* translators: %d: number of historic threats */
149
+ __( 'History (%d)', 'jetpack' ),
150
+ historicThreatsCount
151
+ ) }
152
+ </span>
153
+ }
154
+ />
155
+ </ToggleGroupControl>
156
+ );
157
+ } catch ( error ) {
158
+ return null;
159
+ }
160
+ }
package/index.ts CHANGED
@@ -44,7 +44,9 @@ export { default as CopyToClipboard } from './components/copy-to-clipboard';
44
44
  export * from './components/icons';
45
45
  export { default as SplitButton } from './components/split-button';
46
46
  export { default as ThemeProvider } from './components/theme-provider';
47
+ export { default as ThreatFixerButton } from './components/threat-fixer-button';
47
48
  export { default as ThreatSeverityBadge } from './components/threat-severity-badge';
49
+ export { default as ThreatsDataViews } from './components/threats-data-views';
48
50
  export { default as Text, H2, H3, Title } from './components/text';
49
51
  export { default as ToggleControl } from './components/toggle-control';
50
52
  export { default as numberFormat } from './components/number-format';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/jetpack-components",
3
- "version": "0.58.0",
3
+ "version": "0.59.0",
4
4
  "description": "Jetpack Components Package",
5
5
  "author": "Automattic",
6
6
  "license": "GPL-2.0-or-later",
@@ -15,29 +15,31 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@automattic/format-currency": "1.0.1",
18
- "@automattic/jetpack-boost-score-api": "^0.1.42",
18
+ "@automattic/jetpack-boost-score-api": "^0.1.45",
19
+ "@automattic/jetpack-scan": "^0.1.0",
19
20
  "@babel/runtime": "^7",
20
- "@wordpress/browserslist-config": "6.9.0",
21
- "@wordpress/components": "28.9.0",
22
- "@wordpress/compose": "7.9.0",
23
- "@wordpress/data": "10.9.0",
24
- "@wordpress/date": "5.9.0",
25
- "@wordpress/element": "6.9.0",
26
- "@wordpress/i18n": "5.9.0",
27
- "@wordpress/icons": "10.9.0",
28
- "@wordpress/notices": "5.9.0",
21
+ "@wordpress/browserslist-config": "6.11.0",
22
+ "@wordpress/components": "28.11.0",
23
+ "@wordpress/compose": "7.11.0",
24
+ "@wordpress/data": "10.11.0",
25
+ "@wordpress/dataviews": "4.7.0",
26
+ "@wordpress/date": "5.11.0",
27
+ "@wordpress/element": "6.11.0",
28
+ "@wordpress/i18n": "5.11.0",
29
+ "@wordpress/icons": "10.11.0",
30
+ "@wordpress/notices": "5.11.0",
29
31
  "clsx": "2.1.1",
30
32
  "prop-types": "^15.7.2",
31
33
  "qrcode.react": "3.1.0",
32
34
  "react-slider": "2.0.5",
33
- "social-logos": "^3.1.9",
35
+ "social-logos": "^3.1.11",
34
36
  "uplot": "1.6.31",
35
37
  "uplot-react": "1.1.4"
36
38
  },
37
39
  "devDependencies": {
38
- "@automattic/jetpack-base-styles": "^0.6.34",
39
- "@babel/core": "7.24.7",
40
- "@babel/preset-react": "7.24.7",
40
+ "@automattic/jetpack-base-styles": "^0.6.35",
41
+ "@babel/core": "7.26.0",
42
+ "@babel/preset-react": "7.25.9",
41
43
  "@jest/globals": "29.4.3",
42
44
  "@storybook/addon-actions": "8.3.5",
43
45
  "@storybook/blocks": "8.3.5",
@@ -47,8 +49,8 @@
47
49
  "@testing-library/user-event": "14.5.2",
48
50
  "@types/jest": "29.5.12",
49
51
  "@types/qrcode.react": "1.0.5",
50
- "@types/react": "18.3.3",
51
- "@types/react-dom": "18.3.0",
52
+ "@types/react": "18.3.12",
53
+ "@types/react-dom": "18.3.1",
52
54
  "@types/react-slider": "1.3.6",
53
55
  "jest": "29.7.0",
54
56
  "jest-environment-jsdom": "29.7.0",
@@ -80,6 +82,7 @@
80
82
  "scripts": {
81
83
  "build": "pnpm run compile-ts",
82
84
  "compile-ts": "tsc --pretty",
83
- "test": "NODE_OPTIONS=--experimental-vm-modules jest"
85
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest",
86
+ "test-coverage": "pnpm run test --coverage"
84
87
  }
85
88
  }