@capillarytech/creatives-library 8.0.254 → 8.0.255-alpha.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.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +2 -1
- package/initialReducer.js +2 -0
- package/package.json +1 -1
- package/services/api.js +10 -0
- package/services/tests/api.test.js +34 -0
- package/utils/common.js +5 -0
- package/utils/commonUtils.js +28 -5
- package/utils/tests/commonUtil.test.js +224 -0
- package/utils/transformTemplateConfig.js +0 -10
- package/v2Components/CapDeviceContent/index.js +61 -56
- package/v2Components/CapTagList/index.js +6 -1
- package/v2Components/CapTagListWithInput/index.js +5 -1
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
- package/v2Components/ErrorInfoNote/constants.js +1 -0
- package/v2Components/ErrorInfoNote/index.js +457 -72
- package/v2Components/ErrorInfoNote/messages.js +36 -6
- package/v2Components/ErrorInfoNote/style.scss +282 -6
- package/v2Components/FormBuilder/tests/index.test.js +13 -4
- package/v2Components/HtmlEditor/HTMLEditor.js +547 -94
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +874 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1358 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
- package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
- package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +22 -101
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +149 -140
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +3 -6
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +24 -34
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +50 -34
- package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +70 -41
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +254 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +364 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
- package/v2Components/HtmlEditor/constants.js +42 -20
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +794 -0
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
- package/v2Components/HtmlEditor/hooks/useValidation.js +189 -53
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +95 -85
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +94 -45
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
- package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +134 -102
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
- package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
- package/v2Components/HtmlEditor/utils/validationConstants.js +40 -0
- package/v2Components/MobilePushPreviewV2/index.js +32 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
- package/v2Components/TemplatePreview/index.js +47 -32
- package/v2Components/TemplatePreview/messages.js +4 -0
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
- package/v2Containers/BeeEditor/index.js +172 -90
- package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
- package/v2Containers/BeePopupEditor/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +194 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +128 -51
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +163 -13
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
- package/v2Containers/CreativesContainer/constants.js +1 -0
- package/v2Containers/CreativesContainer/index.js +239 -46
- package/v2Containers/CreativesContainer/messages.js +8 -0
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +106 -0
- package/v2Containers/Email/actions.js +7 -0
- package/v2Containers/Email/constants.js +5 -1
- package/v2Containers/Email/index.js +234 -29
- package/v2Containers/Email/messages.js +32 -0
- package/v2Containers/Email/reducer.js +12 -1
- package/v2Containers/Email/sagas.js +61 -7
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
- package/v2Containers/Email/tests/reducer.test.js +46 -0
- package/v2Containers/Email/tests/sagas.test.js +320 -29
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1285 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +207 -19
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +1870 -0
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
- package/v2Containers/EmailWrapper/constants.js +2 -0
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +629 -77
- package/v2Containers/EmailWrapper/index.js +103 -23
- package/v2Containers/EmailWrapper/messages.js +61 -1
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +643 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +594 -77
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
- package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
- package/v2Containers/InApp/actions.js +7 -0
- package/v2Containers/InApp/constants.js +20 -4
- package/v2Containers/InApp/index.js +802 -359
- package/v2Containers/InApp/index.scss +4 -3
- package/v2Containers/InApp/messages.js +7 -3
- package/v2Containers/InApp/reducer.js +21 -3
- package/v2Containers/InApp/sagas.js +29 -9
- package/v2Containers/InApp/selectors.js +25 -5
- package/v2Containers/InApp/tests/index.test.js +154 -50
- package/v2Containers/InApp/tests/reducer.test.js +34 -0
- package/v2Containers/InApp/tests/sagas.test.js +61 -9
- package/v2Containers/InApp/tests/selectors.test.js +612 -0
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
- package/v2Containers/InAppWrapper/constants.js +16 -0
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
- package/v2Containers/InAppWrapper/index.js +148 -0
- package/v2Containers/InAppWrapper/messages.js +49 -0
- package/v2Containers/InappAdvance/index.js +1099 -0
- package/v2Containers/InappAdvance/index.scss +10 -0
- package/v2Containers/InappAdvance/tests/index.test.js +448 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
- package/v2Containers/TagList/index.js +62 -19
- package/v2Containers/Templates/_templates.scss +60 -1
- package/v2Containers/Templates/index.js +89 -4
- package/v2Containers/Templates/messages.js +4 -0
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ValidationErrorDisplay - HTML Editor validation
|
|
2
|
+
* ValidationErrorDisplay - HTML Editor validation display
|
|
3
3
|
*
|
|
4
|
-
* This component
|
|
5
|
-
*
|
|
4
|
+
* This component displays validation errors using the new ValidationTabs component
|
|
5
|
+
* with tabbed interface for HTML, Label, and Liquid issues.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React from 'react';
|
|
8
|
+
import React, { useState } from 'react';
|
|
9
9
|
import PropTypes from 'prop-types';
|
|
10
10
|
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
import { transformValidationToErrorInfo, hasValidationErrors } from '../../utils/validationAdapter';
|
|
15
|
-
import { HTML_EDITOR_VARIANTS } from '../../constants';
|
|
11
|
+
import { hasValidationErrors } from '../../utils/validationAdapter';
|
|
12
|
+
import ValidationTabs from '../ValidationTabs';
|
|
16
13
|
|
|
17
14
|
// Styles
|
|
18
15
|
import './_validationErrorDisplay.scss';
|
|
@@ -20,51 +17,72 @@ import './_validationErrorDisplay.scss';
|
|
|
20
17
|
/**
|
|
21
18
|
* ValidationErrorDisplay Component
|
|
22
19
|
*
|
|
23
|
-
* Displays validation errors using the
|
|
20
|
+
* Displays validation errors using the ValidationTabs component
|
|
24
21
|
*/
|
|
25
22
|
const ValidationErrorDisplay = ({
|
|
26
23
|
validation,
|
|
27
|
-
variant = HTML_EDITOR_VARIANTS.EMAIL,
|
|
28
24
|
onErrorClick,
|
|
29
|
-
|
|
25
|
+
onClose,
|
|
26
|
+
isLiquidEnabled = false,
|
|
27
|
+
className = '',
|
|
30
28
|
}) => {
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
29
|
+
// Track if panel is dismissed
|
|
30
|
+
const [isDismissed, setIsDismissed] = useState(false);
|
|
35
31
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
onErrorClick?.(error);
|
|
32
|
+
// Handle close - dismiss temporarily
|
|
33
|
+
const handleClose = () => {
|
|
34
|
+
setIsDismissed(true);
|
|
35
|
+
if (onClose) {
|
|
36
|
+
onClose();
|
|
37
|
+
}
|
|
43
38
|
};
|
|
44
39
|
|
|
40
|
+
// Reset dismissed state when validation changes (new errors appear)
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (hasValidationErrors(validation)) {
|
|
43
|
+
setIsDismissed(false);
|
|
44
|
+
}
|
|
45
|
+
}, [validation]);
|
|
46
|
+
|
|
47
|
+
// Don't render if no validation, no errors, or dismissed
|
|
48
|
+
if (!hasValidationErrors(validation) || isDismissed) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
return (
|
|
46
|
-
<
|
|
53
|
+
<div
|
|
47
54
|
className={`validation-error-display ${className}`}
|
|
48
55
|
role="alert"
|
|
49
56
|
aria-live="polite"
|
|
50
57
|
aria-label="Validation errors"
|
|
51
58
|
>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
onErrorClick={
|
|
59
|
+
<ValidationTabs
|
|
60
|
+
validation={validation}
|
|
61
|
+
onErrorClick={onErrorClick}
|
|
62
|
+
onClose={handleClose}
|
|
63
|
+
isLiquidEnabled={isLiquidEnabled}
|
|
55
64
|
/>
|
|
56
|
-
</
|
|
65
|
+
</div>
|
|
57
66
|
);
|
|
58
67
|
};
|
|
59
68
|
|
|
60
69
|
ValidationErrorDisplay.propTypes = {
|
|
61
70
|
validation: PropTypes.shape({
|
|
62
71
|
isValidating: PropTypes.bool,
|
|
63
|
-
getAllIssues: PropTypes.func
|
|
72
|
+
getAllIssues: PropTypes.func,
|
|
64
73
|
}),
|
|
65
|
-
variant: PropTypes.oneOf(Object.values(HTML_EDITOR_VARIANTS)),
|
|
66
74
|
onErrorClick: PropTypes.func,
|
|
67
|
-
|
|
75
|
+
onClose: PropTypes.func,
|
|
76
|
+
isLiquidEnabled: PropTypes.bool,
|
|
77
|
+
className: PropTypes.string,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
ValidationErrorDisplay.defaultProps = {
|
|
81
|
+
validation: null,
|
|
82
|
+
onErrorClick: null,
|
|
83
|
+
onClose: null,
|
|
84
|
+
isLiquidEnabled: false,
|
|
85
|
+
className: '',
|
|
68
86
|
};
|
|
69
87
|
|
|
70
88
|
export default ValidationErrorDisplay;
|
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
@import '~@capillarytech/cap-ui-library/styles/_variables.scss';
|
|
6
6
|
|
|
7
7
|
.validation-panel {
|
|
8
|
-
border: 1px solid
|
|
9
|
-
border-radius:
|
|
10
|
-
background:
|
|
8
|
+
border: 1px solid $CAP_COLOR_16;
|
|
9
|
+
border-radius: $CAP_SPACE_06;
|
|
10
|
+
background: $CAP_WHITE;
|
|
11
11
|
|
|
12
12
|
&--loading {
|
|
13
|
-
padding:
|
|
13
|
+
padding: $CAP_SPACE_16;
|
|
14
14
|
text-align: center;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
&--clean {
|
|
18
|
-
padding:
|
|
18
|
+
padding: $CAP_SPACE_16;
|
|
19
19
|
text-align: center;
|
|
20
20
|
background: #f6ffed;
|
|
21
21
|
border-color: #b7eb8f;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
display: flex;
|
|
26
26
|
align-items: center;
|
|
27
27
|
justify-content: center;
|
|
28
|
-
gap:
|
|
28
|
+
gap: $CAP_SPACE_08;
|
|
29
29
|
color: #666;
|
|
30
30
|
font-size: 14px;
|
|
31
31
|
}
|
|
@@ -34,36 +34,36 @@
|
|
|
34
34
|
display: flex;
|
|
35
35
|
align-items: center;
|
|
36
36
|
justify-content: center;
|
|
37
|
-
gap:
|
|
37
|
+
gap: $CAP_SPACE_08;
|
|
38
38
|
color: #52c41a;
|
|
39
39
|
font-size: 14px;
|
|
40
|
-
font-weight:
|
|
40
|
+
font-weight: $FONT_WEIGHT_MEDIUM;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
&__summary {
|
|
44
44
|
display: flex;
|
|
45
|
-
gap:
|
|
46
|
-
padding:
|
|
47
|
-
background:
|
|
48
|
-
border-bottom: 1px solid
|
|
49
|
-
border-radius:
|
|
45
|
+
gap: $CAP_SPACE_16;
|
|
46
|
+
padding: $CAP_SPACE_12 $CAP_SPACE_16;
|
|
47
|
+
background: $CAP_G21;
|
|
48
|
+
border-bottom: 1px solid $CAP_COLOR_16;
|
|
49
|
+
border-radius: $CAP_SPACE_06 $CAP_SPACE_06 0 0;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
&__summary-item {
|
|
53
53
|
display: flex;
|
|
54
54
|
align-items: center;
|
|
55
|
-
gap:
|
|
56
|
-
font-size:
|
|
55
|
+
gap: $CAP_SPACE_04;
|
|
56
|
+
font-size: $CAP_SPACE_12;
|
|
57
57
|
color: #666;
|
|
58
58
|
|
|
59
59
|
&--security {
|
|
60
60
|
color: #ff4d4f;
|
|
61
|
-
font-weight:
|
|
61
|
+
font-weight: $FONT_WEIGHT_MEDIUM;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
span:first-of-type {
|
|
65
65
|
font-weight: 600;
|
|
66
|
-
margin-left:
|
|
66
|
+
margin-left: $CAP_SPACE_02;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
border: none;
|
|
73
73
|
|
|
74
74
|
&:last-child {
|
|
75
|
-
border-radius: 0 0
|
|
75
|
+
border-radius: 0 0 $CAP_SPACE_06 $CAP_SPACE_06;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -123,8 +123,8 @@
|
|
|
123
123
|
&__title {
|
|
124
124
|
display: flex;
|
|
125
125
|
align-items: center;
|
|
126
|
-
gap:
|
|
127
|
-
font-weight:
|
|
126
|
+
gap: $CAP_SPACE_08;
|
|
127
|
+
font-weight: $FONT_WEIGHT_MEDIUM;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
&__issues {
|
|
@@ -133,41 +133,41 @@
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
&__sanitization {
|
|
136
|
-
border-top: 1px solid
|
|
136
|
+
border-top: 1px solid $CAP_COLOR_16;
|
|
137
137
|
background: #f9f9f9;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
&__sanitization-header {
|
|
141
141
|
display: flex;
|
|
142
142
|
align-items: center;
|
|
143
|
-
gap:
|
|
144
|
-
padding:
|
|
145
|
-
font-weight:
|
|
143
|
+
gap: $CAP_SPACE_08;
|
|
144
|
+
padding: $CAP_SPACE_12 $CAP_SPACE_16;
|
|
145
|
+
font-weight: $FONT_WEIGHT_MEDIUM;
|
|
146
146
|
color: #666;
|
|
147
147
|
font-size: 13px;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
&__sanitization-list {
|
|
151
|
-
padding: 0
|
|
151
|
+
padding: 0 $CAP_SPACE_16 $CAP_SPACE_12;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
&__sanitization-item {
|
|
155
|
-
padding:
|
|
156
|
-
font-size:
|
|
155
|
+
padding: $CAP_SPACE_04 0;
|
|
156
|
+
font-size: $CAP_SPACE_12;
|
|
157
157
|
color: #8c8c8c;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
.validation-issue {
|
|
162
162
|
display: flex;
|
|
163
|
-
gap:
|
|
164
|
-
padding:
|
|
163
|
+
gap: $CAP_SPACE_12;
|
|
164
|
+
padding: $CAP_SPACE_12 $CAP_SPACE_16;
|
|
165
165
|
border-bottom: 1px solid #f0f0f0;
|
|
166
166
|
cursor: pointer;
|
|
167
167
|
transition: background-color 0.2s;
|
|
168
168
|
|
|
169
169
|
&:hover {
|
|
170
|
-
background:
|
|
170
|
+
background: $CAP_G21;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
&:last-child {
|
|
@@ -189,6 +189,22 @@
|
|
|
189
189
|
&__icon {
|
|
190
190
|
flex-shrink: 0;
|
|
191
191
|
margin-top: 2px;
|
|
192
|
+
|
|
193
|
+
&--error {
|
|
194
|
+
color: #ff4d4f;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&--info {
|
|
198
|
+
color: #1890ff;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
&--warning {
|
|
202
|
+
color: #faad14;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
&--security {
|
|
206
|
+
color: #ff4d4f;
|
|
207
|
+
}
|
|
192
208
|
}
|
|
193
209
|
|
|
194
210
|
&__content {
|
|
@@ -200,14 +216,14 @@
|
|
|
200
216
|
font-size: 13px;
|
|
201
217
|
line-height: 1.4;
|
|
202
218
|
color: #262626;
|
|
203
|
-
margin-bottom:
|
|
219
|
+
margin-bottom: $CAP_SPACE_04;
|
|
204
220
|
word-break: break-word;
|
|
205
221
|
}
|
|
206
222
|
|
|
207
223
|
&__meta {
|
|
208
224
|
display: flex;
|
|
209
225
|
flex-wrap: wrap;
|
|
210
|
-
gap:
|
|
226
|
+
gap: $CAP_SPACE_08;
|
|
211
227
|
font-size: 11px;
|
|
212
228
|
color: #8c8c8c;
|
|
213
229
|
}
|
|
@@ -230,9 +246,9 @@
|
|
|
230
246
|
&__source {
|
|
231
247
|
display: flex;
|
|
232
248
|
align-items: center;
|
|
233
|
-
gap:
|
|
249
|
+
gap: $CAP_SPACE_04;
|
|
234
250
|
background: #f0f0f0;
|
|
235
|
-
padding:
|
|
251
|
+
padding: $CAP_SPACE_02 $CAP_SPACE_06;
|
|
236
252
|
border-radius: 3px;
|
|
237
253
|
}
|
|
238
254
|
}
|
|
@@ -21,13 +21,14 @@ import ShieldOutlined from '@ant-design/icons/ShieldOutlined';
|
|
|
21
21
|
import BugOutlined from '@ant-design/icons/BugOutlined';
|
|
22
22
|
import CodeOutlined from '@ant-design/icons/CodeOutlined';
|
|
23
23
|
import EyeInvisibleOutlined from '@ant-design/icons/EyeInvisibleOutlined';
|
|
24
|
-
import
|
|
24
|
+
import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
|
|
25
25
|
|
|
26
26
|
import messages from './messages';
|
|
27
|
+
import { BLOCKING_ERROR_RULE_IDS } from '../../constants';
|
|
27
28
|
import './_validationPanel.scss';
|
|
29
|
+
import { SEVERITY } from './constants';
|
|
28
30
|
|
|
29
31
|
const { Panel } = Collapse;
|
|
30
|
-
|
|
31
32
|
/**
|
|
32
33
|
* ValidationPanel Component
|
|
33
34
|
*/
|
|
@@ -37,7 +38,7 @@ const ValidationPanel = ({
|
|
|
37
38
|
onErrorClick,
|
|
38
39
|
showLineNumbers = true,
|
|
39
40
|
groupBySource = false,
|
|
40
|
-
variant = 'email'
|
|
41
|
+
variant = 'email',
|
|
41
42
|
}) => {
|
|
42
43
|
const [activeKeys, setActiveKeys] = useState(['errors', 'warnings']);
|
|
43
44
|
|
|
@@ -56,31 +57,50 @@ const ValidationPanel = ({
|
|
|
56
57
|
groups[source].push(issue);
|
|
57
58
|
return groups;
|
|
58
59
|
}, {});
|
|
59
|
-
} else {
|
|
60
|
-
return {
|
|
61
|
-
errors: allIssues.filter(issue => issue.severity === 'error'),
|
|
62
|
-
warnings: allIssues.filter(issue => issue.severity === 'warning'),
|
|
63
|
-
info: allIssues.filter(issue => issue.severity === 'info')
|
|
64
|
-
};
|
|
65
60
|
}
|
|
61
|
+
return {
|
|
62
|
+
errors: allIssues.filter((issue) => issue.severity === SEVERITY.ERROR),
|
|
63
|
+
warnings: allIssues.filter((issue) => issue.severity === SEVERITY.WARNING),
|
|
64
|
+
info: allIssues.filter((issue) => issue.severity === SEVERITY.INFO),
|
|
65
|
+
};
|
|
66
66
|
}, [validation, groupBySource]);
|
|
67
67
|
|
|
68
|
+
// Check if an issue is a blocking error (API error, Rule Group #1, or client-side Liquid validation errors)
|
|
69
|
+
const isBlockingError = (issue) => {
|
|
70
|
+
const { rule, source, severity } = issue || {};
|
|
71
|
+
// API errors are blocking
|
|
72
|
+
if (rule === 'liquid-api-validation' || rule === 'standard-api-validation') {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
// Client-side Liquid validation errors are blocking (genuine syntax errors)
|
|
76
|
+
if (source === 'liquid-validator' && severity === 'error') {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
// Rule Group #1 errors are blocking
|
|
80
|
+
if (BLOCKING_ERROR_RULE_IDS.includes(rule)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
};
|
|
85
|
+
|
|
68
86
|
// Get icon for issue type
|
|
69
|
-
|
|
87
|
+
// Blocking errors use error-icon, warnings use alert-warning
|
|
88
|
+
const getIssueIcon = (issue) => {
|
|
89
|
+
const { source, severity } = issue || {};
|
|
70
90
|
if (source === 'security') {
|
|
71
|
-
return <ShieldOutlined
|
|
91
|
+
return <ShieldOutlined className="validation-issue__icon validation-issue__icon--security" />;
|
|
72
92
|
}
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return <BugOutlined style={{ color: '#666' }} />;
|
|
94
|
+
// Only show error icon for blocking errors (API errors or Rule Group #1)
|
|
95
|
+
if (isBlockingError(issue)) {
|
|
96
|
+
return <CapIcon type="error-icon" className="validation-issue__icon validation-issue__icon--error" />;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// All other issues show as warnings
|
|
100
|
+
if (severity === SEVERITY.INFO) {
|
|
101
|
+
return <CapIcon type="info" className="validation-issue__icon validation-issue__icon--info" />;
|
|
83
102
|
}
|
|
103
|
+
return <CapIcon type="alert-warning" className="validation-issue__icon validation-issue__icon--warning" />;
|
|
84
104
|
};
|
|
85
105
|
|
|
86
106
|
// Get source icon
|
|
@@ -106,7 +126,7 @@ const ValidationPanel = ({
|
|
|
106
126
|
line: issue.line,
|
|
107
127
|
column: issue.column || 1,
|
|
108
128
|
message: issue.message,
|
|
109
|
-
severity: issue.severity
|
|
129
|
+
severity: issue.severity,
|
|
110
130
|
});
|
|
111
131
|
}
|
|
112
132
|
};
|
|
@@ -126,7 +146,7 @@ const ValidationPanel = ({
|
|
|
126
146
|
}}
|
|
127
147
|
>
|
|
128
148
|
<div className="validation-issue__icon">
|
|
129
|
-
{getIssueIcon(issue
|
|
149
|
+
{getIssueIcon(issue)}
|
|
130
150
|
</div>
|
|
131
151
|
|
|
132
152
|
<div className="validation-issue__content">
|
|
@@ -137,10 +157,12 @@ const ValidationPanel = ({
|
|
|
137
157
|
<div className="validation-issue__meta">
|
|
138
158
|
{showLineNumbers && issue.line && (
|
|
139
159
|
<span className="validation-issue__location">
|
|
140
|
-
<FormattedMessage
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
160
|
+
<FormattedMessage
|
|
161
|
+
{...messages.lineColumn}
|
|
162
|
+
values={{
|
|
163
|
+
line: issue.line,
|
|
164
|
+
column: issue.column || 1,
|
|
165
|
+
}} />
|
|
144
166
|
</span>
|
|
145
167
|
)}
|
|
146
168
|
|
|
@@ -162,17 +184,24 @@ const ValidationPanel = ({
|
|
|
162
184
|
);
|
|
163
185
|
|
|
164
186
|
// Render panel header with count
|
|
165
|
-
const renderPanelHeader = (title, count, severity) =>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
187
|
+
const renderPanelHeader = (title, count, severity, issues = []) => {
|
|
188
|
+
// Check if any issue in this group is a blocking error
|
|
189
|
+
const hasBlocking = issues.some((issue) => isBlockingError(issue));
|
|
190
|
+
// Use blocking error icon only if there are blocking errors, otherwise use warning icon
|
|
191
|
+
const iconIssue = hasBlocking ? { rule: 'blocking', source: 'blocking' } : { severity: 'warning' };
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<div className="validation-panel__header">
|
|
195
|
+
<span className="validation-panel__title">
|
|
196
|
+
{getIssueIcon(iconIssue)}
|
|
197
|
+
<FormattedMessage {...title} />
|
|
198
|
+
</span>
|
|
199
|
+
{count > 0 && (
|
|
200
|
+
<Badge count={count} style={{ backgroundColor: getSeverityColor(severity) }} />
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
176
205
|
|
|
177
206
|
// Get severity color
|
|
178
207
|
const getSeverityColor = (severity) => {
|
|
@@ -241,14 +270,14 @@ const ValidationPanel = ({
|
|
|
241
270
|
: messages[key] || { id: `htmlEditor.validation.${key}`, defaultMessage: key };
|
|
242
271
|
|
|
243
272
|
const severity = isSourceGroup
|
|
244
|
-
? (issues.find(i => i.severity === 'error') ? 'error'
|
|
245
|
-
|
|
273
|
+
? (issues.find((i) => i.severity === 'error') ? 'error'
|
|
274
|
+
: issues.find((i) => i.severity === 'warning') ? 'warning' : 'info')
|
|
246
275
|
: key;
|
|
247
276
|
|
|
248
277
|
return (
|
|
249
278
|
<Panel
|
|
250
279
|
key={key}
|
|
251
|
-
header={renderPanelHeader(title, issues.length, severity)}
|
|
280
|
+
header={renderPanelHeader(title, issues.length, severity, issues)}
|
|
252
281
|
className={`validation-panel__panel validation-panel__panel--${severity}`}
|
|
253
282
|
>
|
|
254
283
|
<div className="validation-panel__issues">
|
|
@@ -291,7 +320,7 @@ ValidationPanel.propTypes = {
|
|
|
291
320
|
onErrorClick: PropTypes.func,
|
|
292
321
|
showLineNumbers: PropTypes.bool,
|
|
293
322
|
groupBySource: PropTypes.bool,
|
|
294
|
-
variant: PropTypes.oneOf(['email', 'inapp'])
|
|
323
|
+
variant: PropTypes.oneOf(['email', 'inapp']),
|
|
295
324
|
};
|
|
296
325
|
|
|
297
326
|
export default ValidationPanel;
|