@automattic/jetpack-components 0.68.2 → 0.69.1
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.
- package/CHANGELOG.md +10 -0
- package/build/components/action-button/index.d.ts +25 -0
- package/build/components/action-button/index.js +48 -0
- package/build/components/action-popover/index.d.ts +6 -0
- package/build/components/action-popover/index.js +38 -0
- package/build/components/action-popover/types.d.ts +20 -0
- package/build/components/action-popover/types.js +1 -0
- package/build/components/admin-page/index.d.ts +12 -0
- package/build/components/admin-page/index.js +44 -0
- package/build/components/admin-page/types.d.ts +56 -0
- package/build/components/admin-page/types.js +1 -0
- package/build/components/admin-section/basic/index.d.ts +10 -0
- package/build/components/admin-section/basic/index.js +12 -0
- package/build/components/admin-section/hero/index.d.ts +10 -0
- package/build/components/admin-section/hero/index.js +12 -0
- package/build/components/admin-section/types.d.ts +8 -0
- package/build/components/admin-section/types.js +1 -0
- package/build/components/alert/index.d.ts +23 -0
- package/build/components/alert/index.js +33 -0
- package/build/components/automattic-byline-logo/index.d.ts +10 -0
- package/build/components/automattic-byline-logo/index.js +13 -0
- package/build/components/automattic-byline-logo/types.d.ts +15 -0
- package/build/components/automattic-byline-logo/types.js +1 -0
- package/build/components/automattic-for-agencies-logo/index.d.ts +11 -0
- package/build/components/automattic-for-agencies-logo/index.js +12 -0
- package/build/components/automattic-icon-logo/index.d.ts +13 -0
- package/build/components/automattic-icon-logo/index.js +13 -0
- package/build/components/badge/index.d.ts +19 -0
- package/build/components/badge/index.js +22 -0
- package/build/components/boost-score-bar/index.d.ts +5 -0
- package/build/components/boost-score-bar/index.js +35 -0
- package/build/components/boost-score-bar/types.d.ts +9 -0
- package/build/components/boost-score-bar/types.js +1 -0
- package/build/components/boost-score-graph/annotations-plugin.d.ts +16 -0
- package/build/components/boost-score-graph/annotations-plugin.js +58 -0
- package/build/components/boost-score-graph/background.d.ts +3 -0
- package/build/components/boost-score-graph/background.js +5 -0
- package/build/components/boost-score-graph/day-highlight-plugin.d.ts +13 -0
- package/build/components/boost-score-graph/day-highlight-plugin.js +69 -0
- package/build/components/boost-score-graph/get-date-format.d.ts +9 -0
- package/build/components/boost-score-graph/get-date-format.js +52 -0
- package/build/components/boost-score-graph/index.d.ts +44 -0
- package/build/components/boost-score-graph/index.js +42 -0
- package/build/components/boost-score-graph/tooltip.d.ts +3 -0
- package/build/components/boost-score-graph/tooltip.js +22 -0
- package/build/components/boost-score-graph/tooltips-plugin.d.ts +15 -0
- package/build/components/boost-score-graph/tooltips-plugin.js +78 -0
- package/build/components/boost-score-graph/uplot-line-chart.d.ts +27 -0
- package/build/components/boost-score-graph/uplot-line-chart.js +187 -0
- package/build/components/boost-score-graph/use-boost-score-transform.d.ts +14 -0
- package/build/components/boost-score-graph/use-boost-score-transform.js +26 -0
- package/build/components/boost-score-graph/use-resize.d.ts +9 -0
- package/build/components/boost-score-graph/use-resize.js +31 -0
- package/build/components/button/index.d.ts +10 -0
- package/build/components/button/index.js +45 -0
- package/build/components/button/types.d.ts +19 -0
- package/build/components/button/types.js +1 -0
- package/build/components/chip/index.d.ts +15 -0
- package/build/components/chip/index.js +16 -0
- package/build/components/contextual-upgrade-trigger/index.d.ts +4 -0
- package/build/components/contextual-upgrade-trigger/index.js +12 -0
- package/build/components/contextual-upgrade-trigger/types.d.ts +9 -0
- package/build/components/contextual-upgrade-trigger/types.js +1 -0
- package/build/components/copy-to-clipboard/index.d.ts +4 -0
- package/build/components/copy-to-clipboard/index.js +40 -0
- package/build/components/copy-to-clipboard/types.d.ts +6 -0
- package/build/components/copy-to-clipboard/types.js +1 -0
- package/build/components/decorative-card/index.d.ts +11 -0
- package/build/components/decorative-card/index.js +13 -0
- package/build/components/decorative-card/types.d.ts +14 -0
- package/build/components/decorative-card/types.js +1 -0
- package/build/components/dialog/index.d.ts +20 -0
- package/build/components/dialog/index.js +31 -0
- package/build/components/diff-viewer/index.d.ts +4 -0
- package/build/components/diff-viewer/index.js +33 -0
- package/build/components/diff-viewer/parse-filename.d.ts +29 -0
- package/build/components/diff-viewer/parse-filename.js +61 -0
- package/build/components/diff-viewer/parse-patch.d.ts +9 -0
- package/build/components/diff-viewer/parse-patch.js +148 -0
- package/build/components/donut-meter/index.d.ts +58 -0
- package/build/components/donut-meter/index.js +36 -0
- package/build/components/global-notices/global-notices.d.ts +11 -0
- package/build/components/global-notices/global-notices.js +19 -0
- package/build/components/global-notices/index.d.ts +3 -0
- package/build/components/global-notices/index.js +3 -0
- package/build/components/global-notices/use-global-notices.d.ts +10 -0
- package/build/components/global-notices/use-global-notices.js +30 -0
- package/build/components/gridicon/index.d.ts +14 -0
- package/build/components/gridicon/index.js +167 -0
- package/build/components/gridicon/types.d.ts +39 -0
- package/build/components/gridicon/types.js +1 -0
- package/build/components/icon-tooltip/index.d.ts +11 -0
- package/build/components/icon-tooltip/index.js +75 -0
- package/build/components/icon-tooltip/types.d.ts +69 -0
- package/build/components/icon-tooltip/types.js +1 -0
- package/build/components/icons/index.d.ts +70 -0
- package/build/components/icons/index.js +86 -0
- package/build/components/icons/types.d.ts +27 -0
- package/build/components/icons/types.js +1 -0
- package/build/components/indeterminate-progress-bar/index.d.ts +10 -0
- package/build/components/indeterminate-progress-bar/index.js +20 -0
- package/build/components/indeterminate-progress-bar/types.d.ts +6 -0
- package/build/components/indeterminate-progress-bar/types.js +1 -0
- package/build/components/jetpack-footer/index.d.ts +11 -0
- package/build/components/jetpack-footer/index.js +71 -0
- package/build/components/jetpack-footer/types.d.ts +47 -0
- package/build/components/jetpack-footer/types.js +1 -0
- package/build/components/jetpack-logo/index.d.ts +4 -0
- package/build/components/jetpack-logo/index.js +10 -0
- package/build/components/jetpack-logo/types.d.ts +7 -0
- package/build/components/jetpack-logo/types.js +1 -0
- package/build/components/jetpack-protect-logo/index.d.ts +4 -0
- package/build/components/jetpack-protect-logo/index.js +10 -0
- package/build/components/jetpack-protect-logo/types.d.ts +7 -0
- package/build/components/jetpack-protect-logo/types.js +1 -0
- package/build/components/jetpack-search-logo/index.d.ts +4 -0
- package/build/components/jetpack-search-logo/index.js +7 -0
- package/build/components/jetpack-search-logo/types.d.ts +7 -0
- package/build/components/jetpack-search-logo/types.js +1 -0
- package/build/components/jetpack-vaultpress-backup-logo/index.d.ts +4 -0
- package/build/components/jetpack-vaultpress-backup-logo/index.js +8 -0
- package/build/components/jetpack-vaultpress-backup-logo/types.d.ts +6 -0
- package/build/components/jetpack-vaultpress-backup-logo/types.js +1 -0
- package/build/components/jetpack-videopress-logo/index.d.ts +4 -0
- package/build/components/jetpack-videopress-logo/index.js +8 -0
- package/build/components/jetpack-videopress-logo/types.d.ts +6 -0
- package/build/components/jetpack-videopress-logo/types.js +1 -0
- package/build/components/layout/col/index.d.ts +10 -0
- package/build/components/layout/col/index.js +42 -0
- package/build/components/layout/container/index.d.ts +4 -0
- package/build/components/layout/container/index.js +30 -0
- package/build/components/layout/types.d.ts +58 -0
- package/build/components/layout/types.js +1 -0
- package/build/components/layout/use-breakpoint-match/index.d.ts +19 -0
- package/build/components/layout/use-breakpoint-match/index.js +50 -0
- package/build/components/loading-placeholder/index.d.ts +8 -0
- package/build/components/loading-placeholder/index.js +7 -0
- package/build/components/marked-lines/index.d.ts +4 -0
- package/build/components/marked-lines/index.js +50 -0
- package/build/components/notice/index.d.ts +29 -0
- package/build/components/notice/index.js +35 -0
- package/build/components/number-control/index.d.ts +10 -0
- package/build/components/number-control/index.js +16 -0
- package/build/components/number-format/index.d.ts +9 -0
- package/build/components/number-format/index.js +13 -0
- package/build/components/number-slider/index.d.ts +12 -0
- package/build/components/number-slider/index.js +43 -0
- package/build/components/number-slider/types.d.ts +50 -0
- package/build/components/number-slider/types.js +1 -0
- package/build/components/popover/index.d.ts +9 -0
- package/build/components/popover/index.js +6 -0
- package/build/components/pricing-card/index.d.ts +11 -0
- package/build/components/pricing-card/index.js +32 -0
- package/build/components/pricing-card/types.d.ts +51 -0
- package/build/components/pricing-card/types.js +1 -0
- package/build/components/pricing-table/index.d.ts +7 -0
- package/build/components/pricing-table/index.js +66 -0
- package/build/components/pricing-table/types.d.ts +68 -0
- package/build/components/pricing-table/types.js +1 -0
- package/build/components/product-offer/icons-card.d.ts +10 -0
- package/build/components/product-offer/icons-card.js +23 -0
- package/build/components/product-offer/index.d.ts +11 -0
- package/build/components/product-offer/index.js +31 -0
- package/build/components/product-offer/product-offer-header.d.ts +9 -0
- package/build/components/product-offer/product-offer-header.js +14 -0
- package/build/components/product-offer/types.d.ts +102 -0
- package/build/components/product-offer/types.js +1 -0
- package/build/components/product-price/index.d.ts +11 -0
- package/build/components/product-price/index.js +32 -0
- package/build/components/product-price/price.d.ts +9 -0
- package/build/components/product-price/price.js +19 -0
- package/build/components/product-price/types.d.ts +61 -0
- package/build/components/product-price/types.js +1 -0
- package/build/components/progress-bar/index.d.ts +10 -0
- package/build/components/progress-bar/index.js +26 -0
- package/build/components/progress-bar/types.d.ts +18 -0
- package/build/components/progress-bar/types.js +1 -0
- package/build/components/qr-code/index.d.ts +46 -0
- package/build/components/qr-code/index.js +21 -0
- package/build/components/radio-control/index.d.ts +24 -0
- package/build/components/radio-control/index.js +8 -0
- package/build/components/record-meter-bar/index.d.ts +62 -0
- package/build/components/record-meter-bar/index.js +40 -0
- package/build/components/spinner/index.d.ts +13 -0
- package/build/components/spinner/index.js +27 -0
- package/build/components/split-button/index.d.ts +4 -0
- package/build/components/split-button/index.js +8 -0
- package/build/components/split-button/types.d.ts +8 -0
- package/build/components/split-button/types.js +1 -0
- package/build/components/stat-card/index.d.ts +9 -0
- package/build/components/stat-card/index.js +27 -0
- package/build/components/stat-card/types.d.ts +29 -0
- package/build/components/stat-card/types.js +1 -0
- package/build/components/status/index.d.ts +8 -0
- package/build/components/status/index.js +18 -0
- package/build/components/terms-of-service/index.d.ts +5 -0
- package/build/components/terms-of-service/index.js +32 -0
- package/build/components/terms-of-service/types.d.ts +23 -0
- package/build/components/terms-of-service/types.js +1 -0
- package/build/components/testimonials/index.d.ts +3 -0
- package/build/components/testimonials/index.js +18 -0
- package/build/components/testimonials/testimonial.d.ts +4 -0
- package/build/components/testimonials/testimonial.js +7 -0
- package/build/components/testimonials/types.d.ts +13 -0
- package/build/components/testimonials/types.js +1 -0
- package/build/components/text/constants.d.ts +14 -0
- package/build/components/text/constants.js +29 -0
- package/build/components/text/index.d.ts +32 -0
- package/build/components/text/index.js +53 -0
- package/build/components/text/types.d.ts +50 -0
- package/build/components/text/types.js +1 -0
- package/build/components/theme-provider/index.d.ts +80 -0
- package/build/components/theme-provider/index.js +129 -0
- package/build/components/theme-provider/types.d.ts +23 -0
- package/build/components/theme-provider/types.js +1 -0
- package/build/components/threat-fixer-button/index.d.ts +17 -0
- package/build/components/threat-fixer-button/index.js +56 -0
- package/build/components/threat-severity-badge/index.d.ts +4 -0
- package/build/components/threat-severity-badge/index.js +13 -0
- package/build/components/threats-data-views/constants.d.ts +33 -0
- package/build/components/threats-data-views/constants.js +37 -0
- package/build/components/threats-data-views/index.d.ts +30 -0
- package/build/components/threats-data-views/index.js +413 -0
- package/build/components/threats-data-views/threats-status-toggle-group-control.d.ts +16 -0
- package/build/components/threats-data-views/threats-status-toggle-group-control.js +95 -0
- package/build/components/toggle-control/index.d.ts +21 -0
- package/build/components/toggle-control/index.js +21 -0
- package/build/components/upsell-banner/index.d.ts +14 -0
- package/build/components/upsell-banner/index.js +21 -0
- package/build/components/upsell-banner/types.d.ts +13 -0
- package/build/components/upsell-banner/types.js +1 -0
- package/build/components/zendesk-chat/constants.d.ts +1 -0
- package/build/components/zendesk-chat/constants.js +2 -0
- package/build/components/zendesk-chat/index.d.ts +3 -0
- package/build/components/zendesk-chat/index.js +27 -0
- package/build/components/zendesk-chat/types.d.ts +11 -0
- package/build/components/zendesk-chat/types.js +1 -0
- package/build/index.d.ts +67 -0
- package/build/index.js +81 -0
- package/build/lib/locale/index.d.ts +13 -0
- package/build/lib/locale/index.js +34 -0
- package/build/tools/get-product-checkout-url/index.d.ts +10 -0
- package/build/tools/get-product-checkout-url/index.js +22 -0
- package/build/tools/get-site-admin-url/index.d.ts +6 -0
- package/build/tools/get-site-admin-url/index.js +13 -0
- package/build/tools/jp-redirect/index.d.ts +20 -0
- package/build/tools/jp-redirect/index.js +50 -0
- package/build/tools/jp-redirect/types.d.ts +39 -0
- package/build/tools/jp-redirect/types.js +1 -0
- package/build/tools/pricing-utils/index.d.ts +8 -0
- package/build/tools/pricing-utils/index.js +9 -0
- package/build/tools/pricing-utils/types.d.ts +12 -0
- package/build/tools/pricing-utils/types.js +1 -0
- package/components/boost-score-graph/uplot-line-chart.tsx +16 -1
- package/components/jetpack-footer/style.scss +5 -0
- package/components/number-slider/index.tsx +8 -2
- package/package.json +19 -12
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getThreatType } from '@automattic/jetpack-scan';
|
|
3
|
+
import { DataViews, filterSortAndPaginate, } from '@wordpress/dataviews';
|
|
4
|
+
import { dateI18n } from '@wordpress/date';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { Icon } from '@wordpress/icons';
|
|
7
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
8
|
+
import Badge from '../badge/index.js';
|
|
9
|
+
import ThreatFixerButton from '../threat-fixer-button/index.js';
|
|
10
|
+
import ThreatSeverityBadge from '../threat-severity-badge/index.js';
|
|
11
|
+
import { THREAT_ACTION_FIX, THREAT_ACTION_IGNORE, THREAT_ACTION_UNIGNORE, THREAT_FIELD_AUTO_FIX, THREAT_FIELD_DESCRIPTION, THREAT_FIELD_EXTENSION, THREAT_FIELD_FIRST_DETECTED, THREAT_FIELD_FIXED_ON, THREAT_FIELD_ICON, THREAT_FIELD_PLUGIN, THREAT_FIELD_SEVERITY, THREAT_FIELD_SIGNATURE, THREAT_FIELD_STATUS, THREAT_FIELD_THEME, THREAT_FIELD_TITLE, THREAT_FIELD_TYPE, THREAT_ICONS, THREAT_STATUSES, THREAT_TYPES, } from './constants.js';
|
|
12
|
+
import styles from './styles.module.scss';
|
|
13
|
+
import ThreatsStatusToggleGroupControl from './threats-status-toggle-group-control.js';
|
|
14
|
+
/**
|
|
15
|
+
* DataViews component for displaying security threats.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} props - Component props.
|
|
18
|
+
* @param {Array} props.data - Threats data.
|
|
19
|
+
* @param {Array} props.filters - Initial DataView filters.
|
|
20
|
+
* @param {Function} props.onChangeSelection - Callback function run when an item is selected.
|
|
21
|
+
* @param {Function} props.onFixThreats - Threat fix action callback.
|
|
22
|
+
* @param {Function} props.onIgnoreThreats - Threat ignore action callback.
|
|
23
|
+
* @param {Function} props.onUnignoreThreats - Threat unignore action callback.
|
|
24
|
+
* @param {Function} props.isThreatEligibleForFix - Function to determine if a threat is eligible for fixing.
|
|
25
|
+
* @param {Function} props.isThreatEligibleForIgnore - Function to determine if a threat is eligible for ignoring.
|
|
26
|
+
* @param {Function} props.isThreatEligibleForUnignore - Function to determine if a threat is eligible for unignoring.
|
|
27
|
+
*
|
|
28
|
+
* @return {JSX.Element} The ThreatsDataViews component.
|
|
29
|
+
*/
|
|
30
|
+
export default function ThreatsDataViews({ data, filters, onChangeSelection, isThreatEligibleForFix, isThreatEligibleForIgnore, isThreatEligibleForUnignore, onFixThreats, onIgnoreThreats, onUnignoreThreats, }) {
|
|
31
|
+
const baseView = {
|
|
32
|
+
sort: {
|
|
33
|
+
field: 'severity',
|
|
34
|
+
direction: 'desc',
|
|
35
|
+
},
|
|
36
|
+
search: '',
|
|
37
|
+
filters: filters || [],
|
|
38
|
+
page: 1,
|
|
39
|
+
perPage: 20,
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* DataView default layouts.
|
|
43
|
+
*
|
|
44
|
+
* 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.
|
|
45
|
+
*
|
|
46
|
+
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#defaultlayouts-record-string-view
|
|
47
|
+
*/
|
|
48
|
+
const defaultLayouts = {
|
|
49
|
+
table: {
|
|
50
|
+
...baseView,
|
|
51
|
+
fields: [THREAT_FIELD_SEVERITY, THREAT_FIELD_TYPE, THREAT_FIELD_AUTO_FIX],
|
|
52
|
+
titleField: THREAT_FIELD_TITLE,
|
|
53
|
+
descriptionField: THREAT_FIELD_DESCRIPTION,
|
|
54
|
+
showMedia: false,
|
|
55
|
+
},
|
|
56
|
+
list: {
|
|
57
|
+
...baseView,
|
|
58
|
+
fields: [
|
|
59
|
+
THREAT_FIELD_SEVERITY,
|
|
60
|
+
THREAT_FIELD_TYPE,
|
|
61
|
+
THREAT_FIELD_EXTENSION,
|
|
62
|
+
THREAT_FIELD_SIGNATURE,
|
|
63
|
+
],
|
|
64
|
+
titleField: THREAT_FIELD_TITLE,
|
|
65
|
+
mediaField: THREAT_FIELD_ICON,
|
|
66
|
+
showMedia: true,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* DataView view object - configures how the dataset is visible to the user.
|
|
71
|
+
*
|
|
72
|
+
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#view-object
|
|
73
|
+
*/
|
|
74
|
+
const [view, setView] = useState({
|
|
75
|
+
type: 'table',
|
|
76
|
+
...defaultLayouts.table,
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Compute values from the provided threats data.
|
|
80
|
+
*
|
|
81
|
+
* @member {object[]} themes - List of unique themes included in the threats data.
|
|
82
|
+
* @member {object[]} plugins - plugins included in the threats data.
|
|
83
|
+
* @member {object[]} signatures - List of unique threat signatures.
|
|
84
|
+
* @member {string[]} dataFields - List of unique fields.
|
|
85
|
+
*/
|
|
86
|
+
const { themes, plugins, signatures, dataFields, } = useMemo(() => {
|
|
87
|
+
return data.reduce((acc, threat) => {
|
|
88
|
+
// Extensions (Themes and Plugins)
|
|
89
|
+
if (threat.extension) {
|
|
90
|
+
switch (threat.extension.type) {
|
|
91
|
+
case 'themes':
|
|
92
|
+
if (!acc.themes.find(({ value }) => value === threat.extension.slug)) {
|
|
93
|
+
acc.themes.push({ value: threat.extension.slug, label: threat.extension.name });
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
case 'plugins':
|
|
97
|
+
if (!acc.plugins.find(({ value }) => value === threat.extension.slug)) {
|
|
98
|
+
acc.plugins.push({ value: threat.extension.slug, label: threat.extension.name });
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Signatures
|
|
106
|
+
if (threat.signature) {
|
|
107
|
+
if (!acc.signatures.find(({ value }) => value === threat.signature)) {
|
|
108
|
+
acc.signatures.push({ value: threat.signature, label: threat.signature });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Fields
|
|
112
|
+
const fields = Object.keys(threat);
|
|
113
|
+
fields.forEach(field => {
|
|
114
|
+
if (!acc.dataFields.includes(field) &&
|
|
115
|
+
threat[field] !== null &&
|
|
116
|
+
threat[field] !== undefined) {
|
|
117
|
+
acc.dataFields.push(field);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
return acc;
|
|
121
|
+
}, {
|
|
122
|
+
themes: [],
|
|
123
|
+
plugins: [],
|
|
124
|
+
signatures: [],
|
|
125
|
+
dataFields: [],
|
|
126
|
+
});
|
|
127
|
+
}, [data]);
|
|
128
|
+
/**
|
|
129
|
+
* DataView fields - describes the visible items for each record in the dataset.
|
|
130
|
+
*
|
|
131
|
+
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#fields-object
|
|
132
|
+
*/
|
|
133
|
+
const fields = useMemo(() => {
|
|
134
|
+
const result = [
|
|
135
|
+
{
|
|
136
|
+
id: THREAT_FIELD_TITLE,
|
|
137
|
+
label: __('Threat', 'jetpack-components'),
|
|
138
|
+
enableGlobalSearch: true,
|
|
139
|
+
enableHiding: false,
|
|
140
|
+
render: ({ item }) => (_jsx("div", { className: styles.threat__title, children: item.title })),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: THREAT_FIELD_DESCRIPTION,
|
|
144
|
+
label: __('Description', 'jetpack-components'),
|
|
145
|
+
enableGlobalSearch: true,
|
|
146
|
+
enableHiding: false,
|
|
147
|
+
render: ({ item }) => (_jsx("div", { className: styles.threat__description, children: item.description })),
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: THREAT_FIELD_ICON,
|
|
151
|
+
label: __('Icon', 'jetpack-components'),
|
|
152
|
+
enableHiding: false,
|
|
153
|
+
getValue({ item }) {
|
|
154
|
+
return getThreatType(item);
|
|
155
|
+
},
|
|
156
|
+
render({ item }) {
|
|
157
|
+
return (_jsx("div", { className: styles.threat__media, children: _jsx(Icon, { icon: THREAT_ICONS[getThreatType(item)], size: 20 }) }));
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: THREAT_FIELD_STATUS,
|
|
162
|
+
label: __('Status', 'jetpack-components'),
|
|
163
|
+
elements: THREAT_STATUSES,
|
|
164
|
+
getValue({ item }) {
|
|
165
|
+
if (!item.status) {
|
|
166
|
+
return 'current';
|
|
167
|
+
}
|
|
168
|
+
return (THREAT_STATUSES.find(({ value }) => value === item.status)?.value ?? item.status);
|
|
169
|
+
},
|
|
170
|
+
render({ item }) {
|
|
171
|
+
if (item.status) {
|
|
172
|
+
const status = THREAT_STATUSES.find(({ value }) => value === item.status);
|
|
173
|
+
if (status) {
|
|
174
|
+
return _jsx(Badge, { variant: status?.variant, children: status.label });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return _jsx(Badge, { variant: "warning", children: __('Active', 'jetpack-components') });
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: THREAT_FIELD_TYPE,
|
|
182
|
+
label: __('Type', 'jetpack-components'),
|
|
183
|
+
elements: THREAT_TYPES,
|
|
184
|
+
getValue({ item }) {
|
|
185
|
+
switch (getThreatType(item)) {
|
|
186
|
+
case 'core':
|
|
187
|
+
return __('WordPress', 'jetpack-components');
|
|
188
|
+
case 'plugins':
|
|
189
|
+
return __('Plugin', 'jetpack-components');
|
|
190
|
+
case 'themes':
|
|
191
|
+
return __('Theme', 'jetpack-components');
|
|
192
|
+
case 'file':
|
|
193
|
+
return __('File', 'jetpack-components');
|
|
194
|
+
default:
|
|
195
|
+
return __('Unknown', 'jetpack-components');
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: THREAT_FIELD_EXTENSION,
|
|
201
|
+
label: __('Extension', 'jetpack-components'),
|
|
202
|
+
enableGlobalSearch: true,
|
|
203
|
+
enableHiding: true,
|
|
204
|
+
getValue({ item }) {
|
|
205
|
+
return item.extension ? item.extension.slug : '';
|
|
206
|
+
},
|
|
207
|
+
render({ item }) {
|
|
208
|
+
return item.extension ? item.extension.name : '';
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: THREAT_FIELD_PLUGIN,
|
|
213
|
+
label: __('Plugin', 'jetpack-components'),
|
|
214
|
+
enableGlobalSearch: true,
|
|
215
|
+
enableHiding: false,
|
|
216
|
+
elements: plugins,
|
|
217
|
+
getValue({ item }) {
|
|
218
|
+
return item.extension ? item.extension.slug : '';
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: THREAT_FIELD_THEME,
|
|
223
|
+
label: __('Theme', 'jetpack-components'),
|
|
224
|
+
enableGlobalSearch: true,
|
|
225
|
+
enableHiding: false,
|
|
226
|
+
elements: themes,
|
|
227
|
+
getValue({ item }) {
|
|
228
|
+
return item.extension ? item.extension.slug : '';
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
...(dataFields.includes('severity')
|
|
232
|
+
? [
|
|
233
|
+
{
|
|
234
|
+
id: THREAT_FIELD_SEVERITY,
|
|
235
|
+
label: __('Severity', 'jetpack-components'),
|
|
236
|
+
type: 'integer',
|
|
237
|
+
getValue({ item }) {
|
|
238
|
+
return item.severity ?? 0;
|
|
239
|
+
},
|
|
240
|
+
render({ item }) {
|
|
241
|
+
return _jsx(ThreatSeverityBadge, { severity: item.severity });
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
]
|
|
245
|
+
: []),
|
|
246
|
+
...(dataFields.includes('signature')
|
|
247
|
+
? [
|
|
248
|
+
{
|
|
249
|
+
id: THREAT_FIELD_SIGNATURE,
|
|
250
|
+
label: __('Signature', 'jetpack-components'),
|
|
251
|
+
elements: signatures,
|
|
252
|
+
enableGlobalSearch: true,
|
|
253
|
+
getValue({ item }) {
|
|
254
|
+
return item.signature || '';
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
]
|
|
258
|
+
: []),
|
|
259
|
+
...(dataFields.includes('firstDetected')
|
|
260
|
+
? [
|
|
261
|
+
{
|
|
262
|
+
id: THREAT_FIELD_FIRST_DETECTED,
|
|
263
|
+
label: __('First Detected', 'jetpack-components'),
|
|
264
|
+
type: 'datetime',
|
|
265
|
+
getValue({ item }) {
|
|
266
|
+
return item.firstDetected ? new Date(item.firstDetected) : null;
|
|
267
|
+
},
|
|
268
|
+
render({ item }) {
|
|
269
|
+
return item.firstDetected ? (_jsx("span", { className: styles.threat__firstDetected, children: dateI18n('F j Y', item.firstDetected, false) })) : null;
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
]
|
|
273
|
+
: []),
|
|
274
|
+
...(dataFields.includes('fixedOn')
|
|
275
|
+
? [
|
|
276
|
+
{
|
|
277
|
+
id: THREAT_FIELD_FIXED_ON,
|
|
278
|
+
label: __('Fixed On', 'jetpack-components'),
|
|
279
|
+
type: 'datetime',
|
|
280
|
+
getValue({ item }) {
|
|
281
|
+
return item.fixedOn ? new Date(item.fixedOn) : null;
|
|
282
|
+
},
|
|
283
|
+
render({ item }) {
|
|
284
|
+
return item.fixedOn ? (_jsx("span", { className: styles.threat__fixedOn, children: dateI18n('F j Y', item.fixedOn, false) })) : null;
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
]
|
|
288
|
+
: []),
|
|
289
|
+
...(dataFields.includes('fixable')
|
|
290
|
+
? [
|
|
291
|
+
{
|
|
292
|
+
id: THREAT_FIELD_AUTO_FIX,
|
|
293
|
+
label: __('Auto-fix', 'jetpack-components'),
|
|
294
|
+
enableHiding: false,
|
|
295
|
+
elements: [
|
|
296
|
+
{
|
|
297
|
+
value: 'yes',
|
|
298
|
+
label: __('Yes', 'jetpack-components'),
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
value: 'no',
|
|
302
|
+
label: __('No', 'jetpack-components'),
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
getValue({ item }) {
|
|
306
|
+
return item.fixable ? 'yes' : 'no';
|
|
307
|
+
},
|
|
308
|
+
render({ item }) {
|
|
309
|
+
if (!item.fixable) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
return _jsx(ThreatFixerButton, { threat: item, onClick: onFixThreats });
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
]
|
|
316
|
+
: []),
|
|
317
|
+
];
|
|
318
|
+
return result;
|
|
319
|
+
}, [dataFields, plugins, themes, signatures, onFixThreats]);
|
|
320
|
+
/**
|
|
321
|
+
* DataView actions - collection of operations that can be performed upon each record.
|
|
322
|
+
*
|
|
323
|
+
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#actions-object
|
|
324
|
+
*/
|
|
325
|
+
const actions = useMemo(() => {
|
|
326
|
+
const result = [];
|
|
327
|
+
if (dataFields.includes('fixable')) {
|
|
328
|
+
result.push({
|
|
329
|
+
id: THREAT_ACTION_FIX,
|
|
330
|
+
label: __('Auto-fix', 'jetpack-components'),
|
|
331
|
+
isPrimary: true,
|
|
332
|
+
callback: onFixThreats,
|
|
333
|
+
isEligible(item) {
|
|
334
|
+
if (!onFixThreats) {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
if (isThreatEligibleForFix) {
|
|
338
|
+
return isThreatEligibleForFix(item);
|
|
339
|
+
}
|
|
340
|
+
return !!item.fixable;
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
if (dataFields.includes('status')) {
|
|
345
|
+
result.push({
|
|
346
|
+
id: THREAT_ACTION_IGNORE,
|
|
347
|
+
label: __('Ignore', 'jetpack-components'),
|
|
348
|
+
isPrimary: true,
|
|
349
|
+
isDestructive: true,
|
|
350
|
+
callback: onIgnoreThreats,
|
|
351
|
+
isEligible(item) {
|
|
352
|
+
if (!onIgnoreThreats) {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
if (isThreatEligibleForIgnore) {
|
|
356
|
+
return isThreatEligibleForIgnore(item);
|
|
357
|
+
}
|
|
358
|
+
return item.status === 'current';
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (dataFields.includes('status')) {
|
|
363
|
+
result.push({
|
|
364
|
+
id: THREAT_ACTION_UNIGNORE,
|
|
365
|
+
label: __('Unignore', 'jetpack-components'),
|
|
366
|
+
isPrimary: true,
|
|
367
|
+
isDestructive: true,
|
|
368
|
+
callback: onUnignoreThreats,
|
|
369
|
+
isEligible(item) {
|
|
370
|
+
if (!onUnignoreThreats) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
if (isThreatEligibleForUnignore) {
|
|
374
|
+
return isThreatEligibleForUnignore(item);
|
|
375
|
+
}
|
|
376
|
+
return item.status === 'ignored';
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
return result;
|
|
381
|
+
}, [
|
|
382
|
+
dataFields,
|
|
383
|
+
onFixThreats,
|
|
384
|
+
onIgnoreThreats,
|
|
385
|
+
onUnignoreThreats,
|
|
386
|
+
isThreatEligibleForFix,
|
|
387
|
+
isThreatEligibleForIgnore,
|
|
388
|
+
isThreatEligibleForUnignore,
|
|
389
|
+
]);
|
|
390
|
+
/**
|
|
391
|
+
* Apply the view settings (i.e. filters, sorting, pagination) to the dataset.
|
|
392
|
+
*
|
|
393
|
+
* @see https://github.com/WordPress/gutenberg/blob/trunk/packages/dataviews/src/filter-and-sort-data-view.ts
|
|
394
|
+
*/
|
|
395
|
+
const { data: processedData, paginationInfo } = useMemo(() => {
|
|
396
|
+
return filterSortAndPaginate(data, view, fields);
|
|
397
|
+
}, [data, view, fields]);
|
|
398
|
+
/**
|
|
399
|
+
* Callback function to update the view state.
|
|
400
|
+
*
|
|
401
|
+
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#onchangeview-function
|
|
402
|
+
*/
|
|
403
|
+
const onChangeView = useCallback((newView) => {
|
|
404
|
+
setView(newView);
|
|
405
|
+
}, []);
|
|
406
|
+
/**
|
|
407
|
+
* DataView getItemId function - returns the unique ID for each record in the dataset.
|
|
408
|
+
*
|
|
409
|
+
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-dataviews/#getitemid-function
|
|
410
|
+
*/
|
|
411
|
+
const getItemId = useCallback((item) => item.id.toString(), []);
|
|
412
|
+
return (_jsx(DataViews, { actions: actions, data: processedData, defaultLayouts: defaultLayouts, fields: fields, getItemId: getItemId, onChangeSelection: onChangeSelection, onChangeView: onChangeView, paginationInfo: paginationInfo, view: view, header: _jsx(ThreatsStatusToggleGroupControl, { data: data, view: view, onChangeView: onChangeView }) }));
|
|
413
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="react" resolution-mode="require"/>
|
|
2
|
+
import { type Threat } from '@automattic/jetpack-scan';
|
|
3
|
+
import { type View } from '@wordpress/dataviews';
|
|
4
|
+
/**
|
|
5
|
+
* ToggleGroupControl component for filtering threats by status.
|
|
6
|
+
* @param {object} props - Component props.
|
|
7
|
+
* @param { Threat[]} props.data - Threats data.
|
|
8
|
+
* @param { View } props.view - The current view.
|
|
9
|
+
* @param { Function } props.onChangeView - Callback function to handle view changes.
|
|
10
|
+
* @return {JSX.Element|null} The component or null.
|
|
11
|
+
*/
|
|
12
|
+
export default function ThreatsStatusToggleGroupControl({ data, view, onChangeView, }: {
|
|
13
|
+
data: Threat[];
|
|
14
|
+
view: View;
|
|
15
|
+
onChangeView: (newView: View) => void;
|
|
16
|
+
}): JSX.Element;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { __experimentalToggleGroupControl as ToggleGroupControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis
|
|
3
|
+
__experimentalToggleGroupControlOption as ToggleGroupControlOption, // eslint-disable-line @wordpress/no-unsafe-wp-apis
|
|
4
|
+
} from '@wordpress/components';
|
|
5
|
+
import { useMemo, useCallback } from '@wordpress/element';
|
|
6
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
7
|
+
import styles from './styles.module.scss';
|
|
8
|
+
/**
|
|
9
|
+
* ToggleGroupControl component for filtering threats by status.
|
|
10
|
+
* @param {object} props - Component props.
|
|
11
|
+
* @param { Threat[]} props.data - Threats data.
|
|
12
|
+
* @param { View } props.view - The current view.
|
|
13
|
+
* @param { Function } props.onChangeView - Callback function to handle view changes.
|
|
14
|
+
* @return {JSX.Element|null} The component or null.
|
|
15
|
+
*/
|
|
16
|
+
export default function ThreatsStatusToggleGroupControl({ data, view, onChangeView, }) {
|
|
17
|
+
/**
|
|
18
|
+
* Compute values from the provided threats data.
|
|
19
|
+
*
|
|
20
|
+
* @member {number} activeThreatsCount - Count of active threats.
|
|
21
|
+
* @member {number} historicThreatsCount - Count of historic threats.
|
|
22
|
+
*/
|
|
23
|
+
const { activeThreatsCount, historicThreatsCount, } = useMemo(() => {
|
|
24
|
+
return data.reduce((acc, threat) => {
|
|
25
|
+
if (threat.status) {
|
|
26
|
+
if (threat.status === 'current') {
|
|
27
|
+
acc.activeThreatsCount++;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
acc.historicThreatsCount++;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return acc;
|
|
34
|
+
}, {
|
|
35
|
+
activeThreatsCount: 0,
|
|
36
|
+
historicThreatsCount: 0,
|
|
37
|
+
});
|
|
38
|
+
}, [data]);
|
|
39
|
+
/**
|
|
40
|
+
* Callback function to handle the status change filter.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} newStatus - The new status filter value.
|
|
43
|
+
*/
|
|
44
|
+
const onStatusFilterChange = useCallback((newStatus) => {
|
|
45
|
+
const updatedFilters = view.filters.filter(filter => filter.field !== 'status');
|
|
46
|
+
if (newStatus === 'active') {
|
|
47
|
+
updatedFilters.push({
|
|
48
|
+
field: 'status',
|
|
49
|
+
operator: 'isAny',
|
|
50
|
+
value: ['current'],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else if (newStatus === 'historic') {
|
|
54
|
+
updatedFilters.push({
|
|
55
|
+
field: 'status',
|
|
56
|
+
operator: 'isAny',
|
|
57
|
+
value: ['fixed', 'ignored'],
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
onChangeView({
|
|
61
|
+
...view,
|
|
62
|
+
filters: updatedFilters,
|
|
63
|
+
});
|
|
64
|
+
}, [view, onChangeView]);
|
|
65
|
+
/**
|
|
66
|
+
* Memoized function to determine if a status filter is selected.
|
|
67
|
+
*
|
|
68
|
+
* @param {Array} threatStatuses - List of threat statuses.
|
|
69
|
+
*/
|
|
70
|
+
const isStatusFilterSelected = useMemo(() => (threatStatuses) => view.filters.some(filter => filter.field === 'status' &&
|
|
71
|
+
Array.isArray(filter.value) &&
|
|
72
|
+
filter.value.length === threatStatuses.length &&
|
|
73
|
+
threatStatuses.every(threatStatus => filter.value.includes(threatStatus))), [view.filters]);
|
|
74
|
+
const selectedValue = useMemo(() => {
|
|
75
|
+
if (isStatusFilterSelected(['current'])) {
|
|
76
|
+
return 'active';
|
|
77
|
+
}
|
|
78
|
+
if (isStatusFilterSelected(['fixed', 'ignored'])) {
|
|
79
|
+
return 'historic';
|
|
80
|
+
}
|
|
81
|
+
return '';
|
|
82
|
+
}, [isStatusFilterSelected]);
|
|
83
|
+
if (!(activeThreatsCount + historicThreatsCount)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
return (_jsx("div", { children: _jsx("div", { className: styles['toggle-group-control'], children: _jsxs(ToggleGroupControl, { value: selectedValue, onChange: onStatusFilterChange, isBlock: true, hideLabelFromVision: true, __nextHasNoMarginBottom: true, __next40pxDefaultSize: true, children: [_jsx(ToggleGroupControlOption, { value: "active", label: sprintf(
|
|
88
|
+
/* translators: %d: number of active threats */ __('Active threats (%d)', 'jetpack-components'), activeThreatsCount) }), _jsx(ToggleGroupControlOption, { value: "historic", label: sprintf(
|
|
89
|
+
/* translators: %d: number of historic threats */
|
|
90
|
+
__('History (%d)', 'jetpack-components'), historicThreatsCount) })] }) }) }));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="react" resolution-mode="require"/>
|
|
2
|
+
interface ToggleControlProps {
|
|
3
|
+
/** Whether or not the toggle is currently enabled. */
|
|
4
|
+
checked?: boolean;
|
|
5
|
+
/** Custom class name to append to the component. */
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Whether or not the toggle is currently disabled. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** Additional information to display below the toggle. */
|
|
10
|
+
help?: React.ReactNode;
|
|
11
|
+
/** Whether or not the toggling is currently toggling. */
|
|
12
|
+
toggling?: boolean;
|
|
13
|
+
/** The label for the toggle. */
|
|
14
|
+
label?: React.ReactNode;
|
|
15
|
+
/** The size of the toggle. */
|
|
16
|
+
size?: 'small' | 'normal';
|
|
17
|
+
/** A callback function invoked when the toggle is clicked. */
|
|
18
|
+
onChange: (value: boolean) => void;
|
|
19
|
+
}
|
|
20
|
+
declare const ToggleControl: React.FC<ToggleControlProps>;
|
|
21
|
+
export default ToggleControl;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ToggleControl as WPToggleControl } from '@wordpress/components';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { useCallback } from 'react';
|
|
5
|
+
import styles from './styles.module.scss';
|
|
6
|
+
const ToggleControl = ({ checked, className, disabled, help, toggling, label, size = 'normal', onChange, }) => {
|
|
7
|
+
const showChecked = toggling !== undefined ? (checked && !toggling) || (!checked && toggling) : checked;
|
|
8
|
+
const handleOnChange = useCallback((value) => {
|
|
9
|
+
// Don't toggle if the toggle is already toggling.
|
|
10
|
+
if (toggling) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
onChange(value);
|
|
14
|
+
}, [toggling, onChange]);
|
|
15
|
+
return (_jsx(WPToggleControl, { __nextHasNoMarginBottom: true, checked: showChecked, className: clsx(styles.toggle, className, {
|
|
16
|
+
[styles['is-toggling']]: toggling,
|
|
17
|
+
[styles['is-small']]: size === 'small',
|
|
18
|
+
[styles['no-label']]: !label,
|
|
19
|
+
}), disabled: disabled, help: help, label: label, onChange: handleOnChange }));
|
|
20
|
+
};
|
|
21
|
+
export default ToggleControl;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { UpsellBannerProps } from './types.js';
|
|
3
|
+
import './style.scss';
|
|
4
|
+
/**
|
|
5
|
+
* Upsell banner component.
|
|
6
|
+
*
|
|
7
|
+
* - The primary CTA is the second button, at the right position.
|
|
8
|
+
* - The secondary CTA is the first button, at the left position.
|
|
9
|
+
*
|
|
10
|
+
* @param {UpsellBannerProps} props - Component props.
|
|
11
|
+
* @return {React.ReactNode} - UpsellBanner component.
|
|
12
|
+
*/
|
|
13
|
+
declare const UpsellBanner: React.FC<UpsellBannerProps>;
|
|
14
|
+
export default UpsellBanner;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Card, CardBody } from '@wordpress/components';
|
|
3
|
+
import { createInterpolateElement } from '@wordpress/element';
|
|
4
|
+
import { Button } from '@automattic/jetpack-components';
|
|
5
|
+
import './style.scss';
|
|
6
|
+
/**
|
|
7
|
+
* Upsell banner component.
|
|
8
|
+
*
|
|
9
|
+
* - The primary CTA is the second button, at the right position.
|
|
10
|
+
* - The secondary CTA is the first button, at the left position.
|
|
11
|
+
*
|
|
12
|
+
* @param {UpsellBannerProps} props - Component props.
|
|
13
|
+
* @return {React.ReactNode} - UpsellBanner component.
|
|
14
|
+
*/
|
|
15
|
+
const UpsellBanner = props => {
|
|
16
|
+
const { icon, title, description, primaryCtaLabel, primaryCtaURL, primaryCtaIsExternalLink, primaryCtaOnClick, secondaryCtaLabel, secondaryCtaURL, secondaryCtaIsExternalLink, secondaryCtaOnClick, } = props;
|
|
17
|
+
return (_jsx(Card, { isRounded: true, size: "large", children: _jsxs(CardBody, { className: "upsell-banner", size: "large", children: [icon && (_jsx("div", { className: "upsell-banner--icon", children: _jsx("img", { src: icon, alt: "" }) })), _jsxs("div", { className: "upsell-banner--content", children: [_jsxs("div", { className: "upsell-banner--content-info", children: [_jsx("h3", { children: title }), _jsx("p", { children: createInterpolateElement(description, {
|
|
18
|
+
br: _jsx("br", {}),
|
|
19
|
+
}) })] }), _jsxs("div", { className: "upsell-banner--content-cta", children: [secondaryCtaLabel && secondaryCtaURL && (_jsx(Button, { className: "upsell-banner--content-cta-button secondary", href: secondaryCtaURL, onClick: secondaryCtaOnClick ?? undefined, isExternalLink: secondaryCtaIsExternalLink, children: secondaryCtaLabel })), primaryCtaLabel && primaryCtaURL && (_jsx(Button, { className: "upsell-banner--content-cta-button primary", href: primaryCtaURL, onClick: primaryCtaOnClick ?? undefined, isExternalLink: primaryCtaIsExternalLink, children: primaryCtaLabel }))] })] })] }) }));
|
|
20
|
+
};
|
|
21
|
+
export default UpsellBanner;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type UpsellBannerProps = {
|
|
2
|
+
icon?: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
primaryCtaLabel?: string;
|
|
6
|
+
primaryCtaURL?: string;
|
|
7
|
+
primaryCtaIsExternalLink?: boolean;
|
|
8
|
+
primaryCtaOnClick?: () => void;
|
|
9
|
+
secondaryCtaLabel?: string;
|
|
10
|
+
secondaryCtaURL?: string;
|
|
11
|
+
secondaryCtaIsExternalLink?: boolean;
|
|
12
|
+
secondaryCtaOnClick?: () => void;
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const chatKey = "d729d42c-b547-4750-a6f6-8b30534a5f12";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useCallback } from 'react';
|
|
3
|
+
import { chatKey } from './constants.js';
|
|
4
|
+
export const ZendeskChat = ({ jwt_token }) => {
|
|
5
|
+
const authenticateUser = useCallback(() => {
|
|
6
|
+
if (typeof window !== 'undefined' && typeof window.zE === 'function') {
|
|
7
|
+
window.zE('messenger', 'loginUser', function (callback) {
|
|
8
|
+
callback(jwt_token);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
}, [jwt_token]);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
const script = document.createElement('script');
|
|
14
|
+
const container = document.getElementById('zendesk-chat-container');
|
|
15
|
+
script.src = 'https://static.zdassets.com/ekr/snippet.js?key=' + encodeURIComponent(chatKey);
|
|
16
|
+
script.type = 'text/javascript';
|
|
17
|
+
script.id = 'ze-snippet';
|
|
18
|
+
script.onload = () => {
|
|
19
|
+
authenticateUser();
|
|
20
|
+
};
|
|
21
|
+
if (container) {
|
|
22
|
+
container.appendChild(script);
|
|
23
|
+
}
|
|
24
|
+
}, [authenticateUser]);
|
|
25
|
+
return _jsx("div", { "data-testid": "zendesk-chat-container", id: "zendesk-chat-container" });
|
|
26
|
+
};
|
|
27
|
+
export default ZendeskChat;
|