@capillarytech/creatives-library 8.0.259 → 8.0.260-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 (157) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +1 -2
  4. package/initialReducer.js +0 -2
  5. package/package.json +1 -1
  6. package/services/api.js +0 -10
  7. package/services/tests/api.test.js +0 -34
  8. package/translations/en.json +3 -4
  9. package/utils/common.js +0 -12
  10. package/utils/commonUtils.js +5 -28
  11. package/utils/tests/commonUtil.test.js +0 -224
  12. package/utils/transformTemplateConfig.js +10 -0
  13. package/v2Components/CapDeviceContent/index.js +56 -61
  14. package/v2Components/CapTagList/index.js +1 -6
  15. package/v2Components/CapTagListWithInput/index.js +1 -5
  16. package/v2Components/CapTagListWithInput/messages.js +1 -1
  17. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  18. package/v2Components/ErrorInfoNote/index.js +72 -457
  19. package/v2Components/ErrorInfoNote/messages.js +6 -36
  20. package/v2Components/ErrorInfoNote/style.scss +6 -282
  21. package/v2Components/FormBuilder/index.js +4 -4
  22. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  23. package/v2Components/HtmlEditor/HTMLEditor.js +94 -547
  24. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1441
  25. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  26. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  27. package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
  28. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +102 -23
  29. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -148
  30. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  31. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  32. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
  33. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +4 -4
  34. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  35. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  36. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  37. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  38. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  39. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  40. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
  41. package/v2Components/HtmlEditor/components/PreviewPane/index.js +43 -22
  42. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  43. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  44. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +0 -1
  45. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
  46. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -50
  47. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +41 -70
  48. package/v2Components/HtmlEditor/constants.js +20 -42
  49. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  50. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +16 -120
  51. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  52. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  53. package/v2Components/HtmlEditor/hooks/useValidation.js +53 -189
  54. package/v2Components/HtmlEditor/index.js +1 -1
  55. package/v2Components/HtmlEditor/messages.js +94 -92
  56. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -94
  57. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
  58. package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
  59. package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
  60. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +102 -134
  61. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  62. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  63. package/v2Components/MobilePushPreviewV2/index.js +7 -32
  64. package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
  65. package/v2Components/TemplatePreview/index.js +32 -47
  66. package/v2Components/TemplatePreview/messages.js +0 -4
  67. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  68. package/v2Containers/BeeEditor/index.js +90 -172
  69. package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +3 -4
  70. package/v2Containers/CreativesContainer/SlideBoxContent.js +52 -128
  71. package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
  72. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -2
  73. package/v2Containers/CreativesContainer/constants.js +0 -1
  74. package/v2Containers/CreativesContainer/index.js +46 -240
  75. package/v2Containers/CreativesContainer/messages.js +0 -8
  76. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  77. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -38
  78. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -106
  79. package/v2Containers/Email/actions.js +0 -7
  80. package/v2Containers/Email/constants.js +1 -5
  81. package/v2Containers/Email/index.js +30 -239
  82. package/v2Containers/Email/messages.js +0 -32
  83. package/v2Containers/Email/reducer.js +1 -12
  84. package/v2Containers/Email/sagas.js +7 -61
  85. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  86. package/v2Containers/Email/tests/reducer.test.js +0 -46
  87. package/v2Containers/Email/tests/sagas.test.js +29 -320
  88. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +21 -211
  89. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  90. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  91. package/v2Containers/EmailWrapper/constants.js +0 -2
  92. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  93. package/v2Containers/EmailWrapper/index.js +23 -103
  94. package/v2Containers/EmailWrapper/messages.js +1 -65
  95. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  96. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
  97. package/v2Containers/InApp/actions.js +0 -7
  98. package/v2Containers/InApp/constants.js +4 -20
  99. package/v2Containers/InApp/index.js +360 -804
  100. package/v2Containers/InApp/index.scss +3 -4
  101. package/v2Containers/InApp/messages.js +3 -7
  102. package/v2Containers/InApp/reducer.js +3 -21
  103. package/v2Containers/InApp/sagas.js +9 -29
  104. package/v2Containers/InApp/selectors.js +5 -25
  105. package/v2Containers/InApp/tests/index.test.js +71 -152
  106. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  107. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  108. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +12 -39
  109. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +6 -10
  110. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +75 -102
  111. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +54 -81
  112. package/v2Containers/MobilePushNew/index.js +2 -3
  113. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +178 -262
  114. package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +12 -16
  115. package/v2Containers/SmsTrai/Edit/index.js +1 -2
  116. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +111 -468
  117. package/v2Containers/TagList/index.js +19 -62
  118. package/v2Containers/Templates/_templates.scss +1 -60
  119. package/v2Containers/Templates/index.js +4 -89
  120. package/v2Containers/Templates/messages.js +0 -4
  121. package/v2Containers/WebPush/Create/messages.js +8 -0
  122. package/v2Containers/WebPush/Create/preview/PreviewControls.js +2 -2
  123. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +3 -1
  124. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +5 -1
  125. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +5 -1
  126. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +5 -1
  127. package/v2Containers/WebPush/Create/preview/preview.scss +7 -0
  128. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +734 -1306
  129. package/v2Components/ErrorInfoNote/constants.js +0 -1
  130. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -874
  131. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
  132. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -255
  133. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -364
  134. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  135. package/v2Components/HtmlEditor/utils/validationConstants.js +0 -40
  136. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
  137. package/v2Containers/BeePopupEditor/constants.js +0 -10
  138. package/v2Containers/BeePopupEditor/index.js +0 -194
  139. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  140. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1285
  141. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -1880
  142. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  143. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -643
  144. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  145. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  146. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  147. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
  148. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  149. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
  150. package/v2Containers/InAppWrapper/constants.js +0 -16
  151. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  152. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  153. package/v2Containers/InAppWrapper/index.js +0 -148
  154. package/v2Containers/InAppWrapper/messages.js +0 -49
  155. package/v2Containers/InappAdvance/index.js +0 -1099
  156. package/v2Containers/InappAdvance/index.scss +0 -10
  157. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
@@ -1,6 +0,0 @@
1
- // Severity constants
2
- export const SEVERITY = {
3
- ERROR: 'error',
4
- WARNING: 'warning',
5
- INFO: 'info',
6
- };
@@ -1,255 +0,0 @@
1
- /**
2
- * ValidationTabs Styles
3
- */
4
-
5
- @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
6
-
7
- .validation-tabs {
8
- overflow-y: hidden;
9
- width: 100%;
10
- border-radius: 0.25rem;
11
- box-sizing: border-box;
12
-
13
- &__header {
14
- display: flex;
15
- align-items: flex-start;
16
- justify-content: space-between;
17
- width: 100%;
18
- }
19
-
20
- &__tabs {
21
- flex: 1;
22
-
23
- // Override CapTab styles for proper spacing
24
- .cap-tab-v2 {
25
- .ant-tabs-bar {
26
- padding: 0.5rem 0.5rem;
27
- background-color: $CAP_COLOR_05;
28
- }
29
- .ant-tabs-nav {
30
- margin-bottom: 0;
31
-
32
- &::before {
33
- border-bottom: none; // Remove bottom border
34
- }
35
- }
36
-
37
- .ant-tabs-tab {
38
- padding: 0.5rem 0.75rem; // Add horizontal padding for spacing
39
- margin-right: 0; // Remove margin, use padding instead
40
-
41
- color: $CAP_G03;
42
- font-size: 0.875rem;
43
- font-weight: 400;
44
- line-height: 1;
45
- letter-spacing: 0;
46
- background-color: $CAP_COLOR_05;
47
- border-radius: 0.25rem;
48
- border-bottom: none; // Remove bottom border
49
-
50
- & + .ant-tabs-tab {
51
- margin-left: 1.5rem; // Add space between tabs
52
- }
53
-
54
- &:hover {
55
- color: $CAP_COLOR_05;
56
- background-color: $CAP_COLOR_05;
57
- }
58
-
59
- &.ant-tabs-tab-active {
60
- .ant-tabs-tab-btn {
61
- color: $CAP_COLOR_05;
62
- font-weight: 600;
63
- }
64
- }
65
- }
66
-
67
- .ant-tabs-ink-bar {
68
- display: none; // Hide the ink bar (bottom border indicator)
69
- }
70
-
71
- .ant-tabs-content-holder {
72
- padding-top: 0.25rem; // Reduced from 0.5rem
73
- padding-bottom: 0; // No bottom padding
74
- }
75
- }
76
- }
77
-
78
- &__tab-label {
79
- display: flex;
80
- align-items: center;
81
- gap: 0.25rem;
82
- }
83
-
84
- &__tab-count {
85
- color: inherit;
86
- }
87
-
88
- &__actions {
89
- display: flex;
90
- align-items: center;
91
- flex-shrink: 0;
92
- padding-top: 0.5rem;
93
- background-color: $CAP_COLOR_05;
94
- }
95
-
96
- &__close {
97
- display: flex;
98
- align-items: center;
99
- justify-content: center;
100
- width: 1.9rem;
101
- height: 2.3rem;
102
- padding: 0;
103
- background: transparent;
104
- border: none;
105
- border-radius: 0.25rem;
106
- cursor: pointer;
107
- color: $CAP_G03;
108
- transition: all 0.2s ease;
109
-
110
- // &:hover {
111
- // background-color: rgba($CAP_COLOR_05, 0.1);
112
- // color: $CAP_COLOR_05;
113
- // }
114
-
115
- .cap-icon-v2 {
116
- font-size: 0.875rem;
117
- }
118
- }
119
-
120
- &__content {
121
- max-height: 15rem; // Limit height for many errors
122
- overflow-y: auto;
123
- padding-bottom: 0; // Remove bottom padding completely
124
-
125
- // Custom scrollbar
126
- &::-webkit-scrollbar {
127
- width: 0.375rem;
128
- }
129
-
130
- &::-webkit-scrollbar-track {
131
- background: transparent;
132
- }
133
-
134
- &::-webkit-scrollbar-thumb {
135
- background-color: $CAP_G06;
136
- border-radius: 0.1875rem;
137
-
138
- &:hover {
139
- background-color: $CAP_G04;
140
- }
141
- }
142
- }
143
-
144
- &__item {
145
- display: flex;
146
- align-items: flex-start;
147
- gap: 0.5rem;
148
- padding: 0.5rem 0.5rem; // Reduced from 0.375rem
149
- margin-bottom: 3px;
150
-
151
- &:last-child {
152
- border-bottom: none;
153
- padding-bottom: 0.25rem; // Minimal padding on last item
154
- }
155
-
156
- &--error {
157
- .validation-tabs__icon--error {
158
- color: $CAP_RED;
159
- }
160
- }
161
-
162
- &--warning {
163
- .validation-tabs__icon--warning {
164
- color: $CAP_YELLOW;
165
- }
166
- }
167
- }
168
-
169
- &__item-icon {
170
- flex-shrink: 0;
171
- display: flex;
172
- align-items: center;
173
- padding-top: 0.125rem;
174
- }
175
-
176
- &__icon {
177
- font-size: 0.875rem;
178
-
179
- &--error {
180
- color: $CAP_RED;
181
- }
182
-
183
- &--warning {
184
- color: $CAP_YELLOW;
185
- }
186
- }
187
-
188
- &__item-content {
189
- flex: 1;
190
- display: flex;
191
- flex-wrap: wrap;
192
- align-items: baseline;
193
- gap: 0.25rem;
194
- font-size: 0.75rem;
195
- line-height: 2;
196
- color: $CAP_G01;
197
- }
198
-
199
- &__item-message {
200
- color: $CAP_G01;
201
- }
202
-
203
- &__item-location {
204
- color: $CAP_G03;
205
- white-space: nowrap;
206
- }
207
-
208
- &__item-rule {
209
- color: $CAP_G04;
210
- font-family: monospace;
211
- font-size: 0.6875rem;
212
- }
213
-
214
- &__item-navigate {
215
- flex-shrink: 0;
216
- display: flex;
217
- align-items: center;
218
- width: 1.7rem;
219
- height: 1.7rem;
220
- padding: 0;
221
- background: transparent;
222
- border: none;
223
- border-radius: 0.25rem;
224
- cursor: pointer;
225
- color: $CAP_G04;
226
- transition: all 0.2s ease;
227
-
228
- .anticon {
229
- font-size: 1rem; // Increased icon size
230
- }
231
- }
232
- }
233
-
234
- // Responsive adjustments
235
- @media (max-width: 768px) {
236
- .validation-tabs {
237
- padding: 0.375rem 0.5rem;
238
-
239
- &__tabs {
240
- .ant-tabs-tab {
241
- margin-right: 1rem;
242
- font-size: 0.8125rem;
243
- background-color: $CAP_COLOR_05;
244
- }
245
- }
246
-
247
- &__content {
248
- max-height: 10rem;
249
- }
250
-
251
- &__item-content {
252
- font-size: 0.6875rem;
253
- }
254
- }
255
- }
@@ -1,364 +0,0 @@
1
- /**
2
- * ValidationTabs Component
3
- *
4
- * Displays validation errors in a tabbed interface with 3 categories:
5
- * - HTML issues: General HTML/CSS validation errors and warnings
6
- * - Label issues: Tag syntax errors (open/close tags, attributes, brackets)
7
- * - Liquid issues: Liquid expression errors (shown when liquid content is detected, even if liquid feature is disabled)
8
- */
9
-
10
- import React, { useState, useMemo } from 'react';
11
- import PropTypes from 'prop-types';
12
- import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
13
-
14
- // Cap UI Library
15
- import CapRow from '@capillarytech/cap-ui-library/CapRow';
16
- import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
17
- import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
18
-
19
- // Messages
20
- import messages from './messages';
21
- import { BLOCKING_ERROR_RULE_IDS } from '../../constants';
22
- import { ISSUE_SOURCES, LABEL_ISSUE_PATTERNS } from '../../utils/validationConstants';
23
-
24
- // Styles
25
- import './_validationTabs.scss';
26
- import {StyledCapTab} from '../../../../v2Containers/MobilePushNew/style';
27
-
28
- /**
29
- * Categorize issues into HTML, Label, and Liquid categories
30
- */
31
- const categorizeIssues = (allIssues) => {
32
- const htmlIssues = [];
33
- const labelIssues = [];
34
- const liquidIssues = [];
35
-
36
- allIssues.forEach((issue) => {
37
- const { source, rule, message } = issue;
38
- const messageLower = (message || '').toLowerCase();
39
- const ruleLower = (rule || '').toLowerCase();
40
-
41
- // Check if it's a Liquid issue - ONLY by source, not by message content
42
- // This prevents false positives where HTML errors mention liquid syntax
43
- if (source === ISSUE_SOURCES.LIQUID) {
44
- liquidIssues.push(issue);
45
- return;
46
- }
47
-
48
- // Check if it's a Label (tag syntax) issue
49
- const isLabelIssue = LABEL_ISSUE_PATTERNS.some(
50
- (pattern) => messageLower.includes(pattern.toLowerCase())
51
- || ruleLower.includes(pattern.toLowerCase()),
52
- );
53
-
54
- if (isLabelIssue) {
55
- labelIssues.push(issue);
56
- return;
57
- }
58
-
59
- // Default to HTML issues
60
- htmlIssues.push(issue);
61
- });
62
-
63
- return { htmlIssues, labelIssues, liquidIssues };
64
- };
65
-
66
- /**
67
- * Check if an issue is a blocking error (API error, Rule Group #1, or client-side Liquid validation errors)
68
- */
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
-
86
- /**
87
- * Get icon based on whether issue is blocking error or warning
88
- * Blocking errors use error-icon, warnings use alert-warning
89
- */
90
- const getSeverityIcon = (issue) => {
91
- if (isBlockingError(issue)) {
92
- return <CapIcon type="error-icon" className="validation-tabs__icon validation-tabs__icon--error" />;
93
- }
94
- // All other issues (warnings, non-blocking) use warning icon
95
- return <CapIcon type="alert-warning" className="validation-tabs__icon validation-tabs__icon--warning" />;
96
- };
97
-
98
- /**
99
- * ValidationTabContent - Renders the content for each tab
100
- */
101
- const ValidationTabContent = ({
102
- issues,
103
- onErrorClick,
104
- }) => {
105
- if (!issues || issues.length === 0) {
106
- return null;
107
- }
108
-
109
- const handleNavigateClick = (issue, e) => {
110
- e.stopPropagation();
111
- if (onErrorClick) {
112
- // Always call onErrorClick to acknowledge the error (enables buttons)
113
- // If line number exists, navigate to it; otherwise just acknowledge and focus editor
114
- onErrorClick({
115
- line: issue.line || 1, // Default to line 1 if no line number (for API errors)
116
- column: issue.column || 1,
117
- message: issue.message,
118
- severity: issue.severity,
119
- });
120
- }
121
- };
122
-
123
- return (
124
- <div className="validation-tabs__content">
125
- {issues.map((issue, index) => {
126
- const {
127
- message, line, column,
128
- } = issue;
129
- const key = `${message}-${line}-${column}-${index}`;
130
- const isBlocking = isBlockingError(issue);
131
- const displaySeverity = isBlocking ? 'error' : 'warning';
132
-
133
- return (
134
- <div
135
- key={key}
136
- className={`validation-tabs__item validation-tabs__item--${displaySeverity}`}
137
- >
138
- <div className="validation-tabs__item-icon">
139
- {getSeverityIcon(issue)}
140
- </div>
141
- <div className="validation-tabs__item-content">
142
- <span className="validation-tabs__item-message">
143
- {message}
144
- </span>
145
- {line && (
146
- <span className="validation-tabs__item-location">
147
- <FormattedMessage
148
- {...messages.lineChar}
149
- values={{ line, char: column || 1 }}
150
- />
151
- </span>
152
- )}
153
- </div>
154
- {/* Always show redirection icon for errors (even API errors without line numbers) */}
155
- {/* Clicking it acknowledges the error and enables buttons */}
156
- <CapTooltip title={line ? `Line ${line}, Char ${column || 1}` : 'Click to acknowledge error and focus editor'}>
157
- <button
158
- type="button"
159
- className="validation-tabs__item-navigate"
160
- onClick={(e) => handleNavigateClick(issue, e)}
161
- aria-label={line ? `Line ${line}, Char ${column || 1}` : 'Acknowledge error'}
162
- >
163
- <CapIcon type="redirection" />
164
- </button>
165
- </CapTooltip>
166
- </div>
167
- );
168
- })}
169
- </div>
170
- );
171
- };
172
-
173
- ValidationTabContent.propTypes = {
174
- issues: PropTypes.array,
175
- onErrorClick: PropTypes.func,
176
- };
177
-
178
- ValidationTabContent.defaultProps = {
179
- issues: [],
180
- onErrorClick: null,
181
- };
182
-
183
- /**
184
- * ValidationTabs Component
185
- */
186
- const ValidationTabs = ({
187
- intl,
188
- validation,
189
- onErrorClick,
190
- onClose,
191
- className,
192
- }) => {
193
- const [activeKey, setActiveKey] = useState(null);
194
-
195
- // Categorize issues
196
- const { htmlIssues, labelIssues, liquidIssues } = useMemo(() => {
197
- if (!validation) {
198
- return { htmlIssues: [], labelIssues: [], liquidIssues: [] };
199
- }
200
-
201
- // Get all issues from validation
202
- const allIssues = validation.getAllIssues ? validation.getAllIssues() : [];
203
- const categorized = categorizeIssues(allIssues);
204
- return categorized;
205
- }, [validation]);
206
-
207
- // Calculate counts
208
- const htmlCount = htmlIssues.length;
209
- const labelCount = labelIssues.length;
210
- const liquidCount = liquidIssues.length;
211
- // Include liquid issues in total count even when liquid is disabled
212
- // This ensures liquid errors are shown when liquid content is detected but feature is disabled
213
- const totalCount = htmlCount + labelCount + liquidCount;
214
-
215
- // Set default active key when issues change
216
- useMemo(() => {
217
- if (htmlCount > 0 && !activeKey) {
218
- setActiveKey('html');
219
- } else if (labelCount > 0 && !activeKey) {
220
- setActiveKey('label');
221
- } else if (liquidCount > 0 && !activeKey) {
222
- // Show liquid tab even when liquid is disabled if liquid content is detected
223
- setActiveKey('liquid');
224
- }
225
- }, [htmlCount, labelCount, liquidCount, activeKey]);
226
-
227
- // Don't render if no issues
228
- if (totalCount === 0) {
229
- return null;
230
- }
231
-
232
- // Build tab panes (CapTab uses 'panes' with 'tab' and 'content' properties)
233
- const tabPanes = [];
234
-
235
- if (htmlCount > 0) {
236
- tabPanes.push({
237
- key: 'html',
238
- tab: (
239
- <CapTooltip title={`${intl.formatMessage(messages.htmlIssues)} (${htmlCount})`}>
240
- <span className="validation-tabs__tab-label">
241
- <FormattedMessage {...messages.htmlIssues} />
242
- <span className="validation-tabs__tab-count">
243
- (
244
- {htmlCount}
245
- )
246
- </span>
247
- </span>
248
- </CapTooltip>
249
- ),
250
- content: (
251
- <ValidationTabContent
252
- issues={htmlIssues}
253
- onErrorClick={onErrorClick}
254
- intl={intl}
255
- />
256
- ),
257
- });
258
- }
259
-
260
- if (labelCount > 0) {
261
- tabPanes.push({
262
- key: 'label',
263
- tab: (
264
- <CapTooltip title={`${intl.formatMessage(messages.labelIssues)} (${labelCount})`}>
265
- <span className="validation-tabs__tab-label">
266
- <FormattedMessage {...messages.labelIssues} />
267
- <span className="validation-tabs__tab-count">
268
- (
269
- {labelCount}
270
- )
271
- </span>
272
- </span>
273
- </CapTooltip>
274
- ),
275
- content: (
276
- <ValidationTabContent
277
- issues={labelIssues}
278
- onErrorClick={onErrorClick}
279
- intl={intl}
280
- />
281
- ),
282
- });
283
- }
284
-
285
- // Show liquid issues tab even when liquid is disabled if liquid content is detected
286
- // This allows users to see errors when they add liquid content but liquid feature is not enabled
287
- if (liquidCount > 0) {
288
- tabPanes.push({
289
- key: 'liquid',
290
- tab: (
291
- <CapTooltip title={`${intl.formatMessage(messages.liquidIssues)} (${liquidCount})`}>
292
- <span className="validation-tabs__tab-label">
293
- <FormattedMessage {...messages.liquidIssues} />
294
- <span className="validation-tabs__tab-count">
295
- (
296
- {liquidCount}
297
- )
298
- </span>
299
- </span>
300
- </CapTooltip>
301
- ),
302
- content: (
303
- <ValidationTabContent
304
- issues={liquidIssues}
305
- onErrorClick={onErrorClick}
306
- intl={intl}
307
- />
308
- ),
309
- });
310
- }
311
-
312
- // Handle close
313
- const handleClose = () => {
314
- if (onClose) {
315
- onClose();
316
- }
317
- };
318
-
319
- return (
320
- <div className={`validation-tabs ${className || ''}`}>
321
- <CapRow className="validation-tabs__header">
322
- <StyledCapTab
323
- className="validation-tabs__tabs"
324
- activeKey={activeKey || (tabPanes[0]?.key)}
325
- onChange={setActiveKey}
326
- panes={tabPanes}
327
- />
328
- <CapRow className="validation-tabs__actions">
329
- <CapTooltip title={intl.formatMessage(messages.closePanel)}>
330
- <button
331
- type="button"
332
- className="validation-tabs__close"
333
- onClick={handleClose}
334
- aria-label={intl.formatMessage(messages.closePanel)}
335
- >
336
- <CapIcon type="close" />
337
- </button>
338
- </CapTooltip>
339
- </CapRow>
340
- </CapRow>
341
- </div>
342
- );
343
- };
344
-
345
- ValidationTabs.propTypes = {
346
- intl: intlShape.isRequired,
347
- validation: PropTypes.shape({
348
- getAllIssues: PropTypes.func,
349
- }),
350
- onErrorClick: PropTypes.func,
351
- onClose: PropTypes.func,
352
- isLiquidEnabled: PropTypes.bool,
353
- className: PropTypes.string,
354
- };
355
-
356
- ValidationTabs.defaultProps = {
357
- validation: null,
358
- onErrorClick: null,
359
- onClose: null,
360
- isLiquidEnabled: false,
361
- className: '',
362
- };
363
-
364
- export default injectIntl(ValidationTabs);
@@ -1,51 +0,0 @@
1
- /**
2
- * ValidationTabs Messages
3
- *
4
- * Internationalization messages for the ValidationTabs component
5
- */
6
-
7
- import { defineMessages } from 'react-intl';
8
-
9
- const scope = 'app.components.HtmlEditor.ValidationTabs';
10
-
11
- export default defineMessages({
12
- // Tab labels
13
- htmlIssues: {
14
- id: `${scope}.htmlIssues`,
15
- defaultMessage: 'HTML issues',
16
- },
17
- labelIssues: {
18
- id: `${scope}.labelIssues`,
19
- defaultMessage: 'Label issues',
20
- },
21
- liquidIssues: {
22
- id: `${scope}.liquidIssues`,
23
- defaultMessage: 'Liquid issues',
24
- },
25
-
26
- // Error item labels
27
- syntaxError: {
28
- id: `${scope}.syntaxError`,
29
- defaultMessage: 'Syntax Error',
30
- },
31
- lineChar: {
32
- id: `${scope}.lineChar`,
33
- defaultMessage: 'Line {line}, Char {char}.',
34
- },
35
-
36
- // Tooltips
37
- navigateToError: {
38
- id: `${scope}.navigateToError`,
39
- defaultMessage: 'Go to error location',
40
- },
41
- closePanel: {
42
- id: `${scope}.closePanel`,
43
- defaultMessage: 'Close validation panel',
44
- },
45
-
46
- // Liquid documentation
47
- liquidDocumentation: {
48
- id: `${scope}.liquidDocumentation`,
49
- defaultMessage: 'Liquid documentation',
50
- },
51
- });
@@ -1,40 +0,0 @@
1
- /**
2
- * Validation Constants
3
- *
4
- * Shared constants for validation issue categorization across HTML Editor components
5
- */
6
-
7
- // Issue sources for categorizing validation errors
8
- export const ISSUE_SOURCES = {
9
- HTMLHINT: 'htmlhint',
10
- CSS_VALIDATOR: 'css-validator',
11
- CUSTOM: 'custom',
12
- SECURITY: 'security',
13
- LIQUID: 'liquid-validator',
14
- };
15
-
16
- // Label issue patterns - syntax errors related to tags
17
- // These patterns identify tag syntax errors (open/close tags, attributes, brackets)
18
- export const LABEL_ISSUE_PATTERNS = [
19
- 'tag must be paired',
20
- 'open tag match failed',
21
- 'closed tag match failed',
22
- 'unclosed',
23
- 'missing required',
24
- 'tag-pair',
25
- 'attr-value-not-empty',
26
- 'attr-no-duplication',
27
- 'tag-self-close',
28
- 'spec-char-escape',
29
- 'tagname-lowercase',
30
- 'attr-lowercase',
31
- 'src-not-empty',
32
- 'alt-require',
33
- ];
34
-
35
- // Tab keys for error categorization
36
- export const ERROR_TAB_KEYS = {
37
- HTML: 'html',
38
- LABEL: 'label',
39
- LIQUID: 'liquid',
40
- };