@capillarytech/creatives-library 8.0.249 → 8.0.250-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 +18 -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/index.js +452 -72
- package/v2Components/ErrorInfoNote/messages.js +22 -0
- package/v2Components/ErrorInfoNote/style.scss +280 -4
- package/v2Components/FormBuilder/tests/index.test.js +13 -4
- package/v2Components/HtmlEditor/HTMLEditor.js +640 -94
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +874 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1167 -133
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
- package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +13 -101
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -139
- 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 +11 -13
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +49 -31
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +68 -39
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +254 -0
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +391 -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 +795 -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/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/MobilePushPreviewV2/index.js +32 -7
- package/v2Components/TemplatePreview/_templatePreview.scss +44 -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/constants.js +10 -0
- package/v2Containers/BeePopupEditor/index.js +193 -0
- package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
- package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -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 +222 -27
- 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/sagas.test.js +320 -29
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1321 -0
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +210 -15
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +1749 -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 +162 -0
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +9 -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;
|
|
@@ -21,9 +21,10 @@ 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';
|
|
28
29
|
|
|
29
30
|
const { Panel } = Collapse;
|
|
@@ -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 === 'error'),
|
|
63
|
+
warnings: allIssues.filter((issue) => issue.severity === 'warning'),
|
|
64
|
+
info: allIssues.filter((issue) => issue.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
91
|
return <ShieldOutlined style={{ color: '#ff4d4f' }} />;
|
|
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" style={{ color: '#ff4d4f' }} />;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// All other issues show as warnings
|
|
100
|
+
if (severity === 'info') {
|
|
101
|
+
return <CapIcon type="info" style={{ color: '#1890ff' }} />;
|
|
83
102
|
}
|
|
103
|
+
return <CapIcon type="alert-warning" style={{ color: '#faad14' }} />;
|
|
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;
|
|
@@ -0,0 +1,254 @@
|
|
|
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
|
+
background-color: $CAP_COLOR_05; // Light pink background
|
|
11
|
+
border-radius: 0.25rem;
|
|
12
|
+
padding: 1rem 1rem;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
|
|
15
|
+
&__header {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: flex-start;
|
|
18
|
+
justify-content: space-between;
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&__tabs {
|
|
23
|
+
flex: 1;
|
|
24
|
+
|
|
25
|
+
// Override CapTab styles for proper spacing
|
|
26
|
+
.cap-tab-v2 {
|
|
27
|
+
.ant-tabs-nav {
|
|
28
|
+
margin-bottom: 0;
|
|
29
|
+
|
|
30
|
+
&::before {
|
|
31
|
+
border-bottom: none;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.ant-tabs-tab {
|
|
36
|
+
padding: 0.5rem 0.75rem; // Add horizontal padding for spacing
|
|
37
|
+
margin-right: 0; // Remove margin, use padding instead
|
|
38
|
+
color: $CAP_G03;
|
|
39
|
+
font-size: 0.875rem;
|
|
40
|
+
font-weight: 500;
|
|
41
|
+
|
|
42
|
+
& + .ant-tabs-tab {
|
|
43
|
+
margin-left: 1.5rem; // Add space between tabs
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&:hover {
|
|
47
|
+
color: $CAP_COLOR_05;
|
|
48
|
+
background: transparent;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&.ant-tabs-tab-active {
|
|
52
|
+
.ant-tabs-tab-btn {
|
|
53
|
+
color: $CAP_COLOR_05;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ant-tabs-ink-bar {
|
|
60
|
+
background-color: $CAP_COLOR_05;
|
|
61
|
+
height: 0.125rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ant-tabs-content-holder {
|
|
65
|
+
padding-top: 0.25rem; // Reduced from 0.5rem
|
|
66
|
+
padding-bottom: 0; // No bottom padding
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&__tab-label {
|
|
72
|
+
display: flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
gap: 0.25rem;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&__tab-count {
|
|
78
|
+
color: inherit;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&__actions {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: 0.5rem;
|
|
85
|
+
flex-shrink: 0;
|
|
86
|
+
padding-top: 0.5rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&__close {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
width: 1.5rem;
|
|
94
|
+
height: 1.5rem;
|
|
95
|
+
padding: 0;
|
|
96
|
+
background: transparent;
|
|
97
|
+
border: none;
|
|
98
|
+
border-radius: 0.25rem;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
color: $CAP_G03;
|
|
101
|
+
transition: all 0.2s ease;
|
|
102
|
+
|
|
103
|
+
&:hover {
|
|
104
|
+
background-color: rgba($CAP_COLOR_05, 0.1);
|
|
105
|
+
color: $CAP_COLOR_05;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.cap-icon-v2 {
|
|
109
|
+
font-size: 0.875rem;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
&__content {
|
|
114
|
+
max-height: 15rem; // Limit height for many errors
|
|
115
|
+
overflow-y: auto;
|
|
116
|
+
padding-right: 0.25rem;
|
|
117
|
+
padding-bottom: 0; // Remove bottom padding completely
|
|
118
|
+
|
|
119
|
+
// Custom scrollbar
|
|
120
|
+
&::-webkit-scrollbar {
|
|
121
|
+
width: 0.375rem;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&::-webkit-scrollbar-track {
|
|
125
|
+
background: transparent;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&::-webkit-scrollbar-thumb {
|
|
129
|
+
background-color: $CAP_G06;
|
|
130
|
+
border-radius: 0.1875rem;
|
|
131
|
+
|
|
132
|
+
&:hover {
|
|
133
|
+
background-color: $CAP_G04;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&__item {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: flex-start;
|
|
141
|
+
gap: 0.5rem;
|
|
142
|
+
padding: 0.25rem 0; // Reduced from 0.375rem
|
|
143
|
+
border-bottom: 1px solid rgba($CAP_G06, 0.3);
|
|
144
|
+
|
|
145
|
+
&:last-child {
|
|
146
|
+
border-bottom: none;
|
|
147
|
+
padding-bottom: 0.25rem; // Minimal padding on last item
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&--error {
|
|
151
|
+
.validation-tabs__icon--error {
|
|
152
|
+
color: $CAP_RED;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
&--warning {
|
|
157
|
+
.validation-tabs__icon--warning {
|
|
158
|
+
color: $CAP_YELLOW;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
&__item-icon {
|
|
164
|
+
flex-shrink: 0;
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
padding-top: 0.125rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&__icon {
|
|
171
|
+
font-size: 0.875rem;
|
|
172
|
+
|
|
173
|
+
&--error {
|
|
174
|
+
color: $CAP_RED;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
&--warning {
|
|
178
|
+
color: $CAP_YELLOW;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&__item-content {
|
|
183
|
+
flex: 1;
|
|
184
|
+
display: flex;
|
|
185
|
+
flex-wrap: wrap;
|
|
186
|
+
align-items: baseline;
|
|
187
|
+
gap: 0.25rem;
|
|
188
|
+
font-size: 0.75rem;
|
|
189
|
+
line-height: 1.4;
|
|
190
|
+
color: $CAP_G01;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
&__item-message {
|
|
194
|
+
color: $CAP_G01;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
&__item-location {
|
|
198
|
+
color: $CAP_G03;
|
|
199
|
+
white-space: nowrap;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&__item-rule {
|
|
203
|
+
color: $CAP_G04;
|
|
204
|
+
font-family: monospace;
|
|
205
|
+
font-size: 0.6875rem;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
&__item-navigate {
|
|
209
|
+
flex-shrink: 0;
|
|
210
|
+
display: flex;
|
|
211
|
+
align-items: center;
|
|
212
|
+
justify-content: center;
|
|
213
|
+
width: 1.25rem;
|
|
214
|
+
height: 1.25rem;
|
|
215
|
+
padding: 0;
|
|
216
|
+
background: transparent;
|
|
217
|
+
border: none;
|
|
218
|
+
border-radius: 0.25rem;
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
color: $CAP_G04;
|
|
221
|
+
transition: all 0.2s ease;
|
|
222
|
+
|
|
223
|
+
&:hover {
|
|
224
|
+
background-color: rgba($CAP_G01, 0.1);
|
|
225
|
+
color: $CAP_G01;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.anticon {
|
|
229
|
+
font-size: 0.75rem;
|
|
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
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
&__content {
|
|
247
|
+
max-height: 10rem;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
&__item-content {
|
|
251
|
+
font-size: 0.6875rem;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|