@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.
Files changed (143) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +2 -1
  4. package/initialReducer.js +2 -0
  5. package/package.json +1 -1
  6. package/services/api.js +10 -0
  7. package/services/tests/api.test.js +34 -0
  8. package/utils/common.js +5 -0
  9. package/utils/commonUtils.js +28 -5
  10. package/utils/tests/commonUtil.test.js +224 -0
  11. package/utils/transformTemplateConfig.js +0 -10
  12. package/v2Components/CapDeviceContent/index.js +61 -56
  13. package/v2Components/CapTagList/index.js +6 -1
  14. package/v2Components/CapTagListWithInput/index.js +5 -1
  15. package/v2Components/CapTagListWithInput/messages.js +1 -1
  16. package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
  17. package/v2Components/ErrorInfoNote/constants.js +1 -0
  18. package/v2Components/ErrorInfoNote/index.js +457 -72
  19. package/v2Components/ErrorInfoNote/messages.js +36 -6
  20. package/v2Components/ErrorInfoNote/style.scss +282 -6
  21. package/v2Components/FormBuilder/tests/index.test.js +13 -4
  22. package/v2Components/HtmlEditor/HTMLEditor.js +547 -94
  23. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +874 -0
  24. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1358 -133
  25. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
  26. package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
  27. package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
  28. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +22 -101
  29. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +149 -140
  30. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
  31. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  32. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -0
  33. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
  34. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
  35. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
  36. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
  37. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
  38. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  39. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
  40. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +3 -6
  41. package/v2Components/HtmlEditor/components/PreviewPane/index.js +24 -34
  42. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  43. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
  44. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +50 -34
  45. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
  46. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +70 -41
  47. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +254 -0
  48. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +364 -0
  49. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
  50. package/v2Components/HtmlEditor/constants.js +42 -20
  51. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
  52. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +794 -0
  53. package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
  54. package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
  55. package/v2Components/HtmlEditor/hooks/useValidation.js +189 -53
  56. package/v2Components/HtmlEditor/index.js +1 -1
  57. package/v2Components/HtmlEditor/messages.js +95 -85
  58. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +94 -45
  59. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
  60. package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
  61. package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
  62. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +134 -102
  63. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
  64. package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
  65. package/v2Components/HtmlEditor/utils/validationConstants.js +40 -0
  66. package/v2Components/MobilePushPreviewV2/index.js +32 -7
  67. package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
  68. package/v2Components/TemplatePreview/index.js +47 -32
  69. package/v2Components/TemplatePreview/messages.js +4 -0
  70. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
  71. package/v2Containers/BeeEditor/index.js +172 -90
  72. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
  73. package/v2Containers/BeePopupEditor/constants.js +10 -0
  74. package/v2Containers/BeePopupEditor/index.js +194 -0
  75. package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
  76. package/v2Containers/CreativesContainer/SlideBoxContent.js +128 -51
  77. package/v2Containers/CreativesContainer/SlideBoxFooter.js +163 -13
  78. package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
  79. package/v2Containers/CreativesContainer/constants.js +1 -0
  80. package/v2Containers/CreativesContainer/index.js +239 -46
  81. package/v2Containers/CreativesContainer/messages.js +8 -0
  82. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
  83. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
  84. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +106 -0
  85. package/v2Containers/Email/actions.js +7 -0
  86. package/v2Containers/Email/constants.js +5 -1
  87. package/v2Containers/Email/index.js +234 -29
  88. package/v2Containers/Email/messages.js +32 -0
  89. package/v2Containers/Email/reducer.js +12 -1
  90. package/v2Containers/Email/sagas.js +61 -7
  91. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
  92. package/v2Containers/Email/tests/reducer.test.js +46 -0
  93. package/v2Containers/Email/tests/sagas.test.js +320 -29
  94. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1285 -0
  95. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +207 -19
  96. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
  97. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +1870 -0
  98. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
  99. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
  100. package/v2Containers/EmailWrapper/constants.js +2 -0
  101. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +629 -77
  102. package/v2Containers/EmailWrapper/index.js +103 -23
  103. package/v2Containers/EmailWrapper/messages.js +61 -1
  104. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +643 -0
  105. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +594 -77
  106. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
  107. package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
  108. package/v2Containers/InApp/actions.js +7 -0
  109. package/v2Containers/InApp/constants.js +20 -4
  110. package/v2Containers/InApp/index.js +802 -359
  111. package/v2Containers/InApp/index.scss +4 -3
  112. package/v2Containers/InApp/messages.js +7 -3
  113. package/v2Containers/InApp/reducer.js +21 -3
  114. package/v2Containers/InApp/sagas.js +29 -9
  115. package/v2Containers/InApp/selectors.js +25 -5
  116. package/v2Containers/InApp/tests/index.test.js +154 -50
  117. package/v2Containers/InApp/tests/reducer.test.js +34 -0
  118. package/v2Containers/InApp/tests/sagas.test.js +61 -9
  119. package/v2Containers/InApp/tests/selectors.test.js +612 -0
  120. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
  121. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
  122. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
  123. package/v2Containers/InAppWrapper/constants.js +16 -0
  124. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
  125. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
  126. package/v2Containers/InAppWrapper/index.js +148 -0
  127. package/v2Containers/InAppWrapper/messages.js +49 -0
  128. package/v2Containers/InappAdvance/index.js +1099 -0
  129. package/v2Containers/InappAdvance/index.scss +10 -0
  130. package/v2Containers/InappAdvance/tests/index.test.js +448 -0
  131. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
  132. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
  133. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
  134. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
  135. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
  136. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
  137. package/v2Containers/TagList/index.js +62 -19
  138. package/v2Containers/Templates/_templates.scss +60 -1
  139. package/v2Containers/Templates/index.js +89 -4
  140. package/v2Containers/Templates/messages.js +4 -0
  141. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -0
  142. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
  143. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
@@ -1,18 +1,15 @@
1
1
  /**
2
- * ValidationErrorDisplay - HTML Editor validation using ErrorInfoNote
2
+ * ValidationErrorDisplay - HTML Editor validation display
3
3
  *
4
- * This component integrates the existing ErrorInfoNote component with the HTML Editor's
5
- * validation system, providing a consistent error display that matches the Figma design.
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 CapRow from '@capillarytech/cap-ui-library/CapRow';
12
- import ErrorInfoNote from '../../../ErrorInfoNote';
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 existing ErrorInfoNote component
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
- className = ''
25
+ onClose,
26
+ isLiquidEnabled = false,
27
+ className = '',
30
28
  }) => {
31
- // Don't render if no validation or no errors
32
- if (!hasValidationErrors(validation)) {
33
- return null;
34
- }
29
+ // Track if panel is dismissed
30
+ const [isDismissed, setIsDismissed] = useState(false);
35
31
 
36
- // Transform validation data to ErrorInfoNote format
37
- const errorData = transformValidationToErrorInfo(validation, variant);
38
- const { errorMessages } = errorData || {};
39
-
40
- // Handle error click if provided
41
- const handleErrorClick = (error) => {
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
- <CapRow
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
- <ErrorInfoNote
53
- errorMessages={errorMessages}
54
- onErrorClick={handleErrorClick}
59
+ <ValidationTabs
60
+ validation={validation}
61
+ onErrorClick={onErrorClick}
62
+ onClose={handleClose}
63
+ isLiquidEnabled={isLiquidEnabled}
55
64
  />
56
- </CapRow>
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
- className: PropTypes.string
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 #d9d9d9;
9
- border-radius: 6px;
10
- background: #fff;
8
+ border: 1px solid $CAP_COLOR_16;
9
+ border-radius: $CAP_SPACE_06;
10
+ background: $CAP_WHITE;
11
11
 
12
12
  &--loading {
13
- padding: 16px;
13
+ padding: $CAP_SPACE_16;
14
14
  text-align: center;
15
15
  }
16
16
 
17
17
  &--clean {
18
- padding: 16px;
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: 8px;
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: 8px;
37
+ gap: $CAP_SPACE_08;
38
38
  color: #52c41a;
39
39
  font-size: 14px;
40
- font-weight: 500;
40
+ font-weight: $FONT_WEIGHT_MEDIUM;
41
41
  }
42
42
 
43
43
  &__summary {
44
44
  display: flex;
45
- gap: 16px;
46
- padding: 12px 16px;
47
- background: #fafafa;
48
- border-bottom: 1px solid #d9d9d9;
49
- border-radius: 6px 6px 0 0;
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: 4px;
56
- font-size: 12px;
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: 500;
61
+ font-weight: $FONT_WEIGHT_MEDIUM;
62
62
  }
63
63
 
64
64
  span:first-of-type {
65
65
  font-weight: 600;
66
- margin-left: 2px;
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 6px 6px;
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: 8px;
127
- font-weight: 500;
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 #d9d9d9;
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: 8px;
144
- padding: 12px 16px;
145
- font-weight: 500;
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 16px 12px;
151
+ padding: 0 $CAP_SPACE_16 $CAP_SPACE_12;
152
152
  }
153
153
 
154
154
  &__sanitization-item {
155
- padding: 4px 0;
156
- font-size: 12px;
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: 12px;
164
- padding: 12px 16px;
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: #fafafa;
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: 4px;
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: 8px;
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: 4px;
249
+ gap: $CAP_SPACE_04;
234
250
  background: #f0f0f0;
235
- padding: 2px 6px;
251
+ padding: $CAP_SPACE_02 $CAP_SPACE_06;
236
252
  border-radius: 3px;
237
253
  }
238
254
  }
@@ -0,0 +1,6 @@
1
+ // Severity constants
2
+ export const SEVERITY = {
3
+ ERROR: 'error',
4
+ WARNING: 'warning',
5
+ INFO: 'info',
6
+ };
@@ -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 CheckCircleOutlined from '@ant-design/icons/CheckCircleOutlined';
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
- const getIssueIcon = (severity, source) => {
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 style={{ color: '#ff4d4f' }} />;
91
+ return <ShieldOutlined className="validation-issue__icon validation-issue__icon--security" />;
72
92
  }
73
93
 
74
- switch (severity) {
75
- case 'error':
76
- return <ExclamationCircleOutlined style={{ color: '#ff4d4f' }} />;
77
- case 'warning':
78
- return <WarningOutlined style={{ color: '#faad14' }} />;
79
- case 'info':
80
- return <InfoCircleOutlined style={{ color: '#1890ff' }} />;
81
- default:
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.severity, issue.source)}
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 {...messages.lineColumn} values={{
141
- line: issue.line,
142
- column: issue.column || 1
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
- <div className="validation-panel__header">
167
- <span className="validation-panel__title">
168
- {getIssueIcon(severity)}
169
- <FormattedMessage {...title} />
170
- </span>
171
- {count > 0 && (
172
- <Badge count={count} style={{ backgroundColor: getSeverityColor(severity) }} />
173
- )}
174
- </div>
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
- issues.find(i => i.severity === 'warning') ? 'warning' : 'info')
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;