@capillarytech/creatives-library 8.0.262 → 8.0.263
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/package.json +1 -1
- package/v2Components/ErrorInfoNote/index.js +1 -1
- package/v2Components/HtmlEditor/HTMLEditor.js +3 -1
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -1
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +27 -2
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +4 -3
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +3 -2
- package/v2Components/HtmlEditor/constants.js +3 -0
- package/v2Components/HtmlEditor/hooks/useValidation.js +11 -10
- package/v2Components/HtmlEditor/messages.js +10 -0
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +38 -36
- package/v2Components/MobilePushPreviewV2/constants.js +6 -0
- package/v2Components/MobilePushPreviewV2/index.js +4 -3
package/package.json
CHANGED
|
@@ -406,7 +406,7 @@ const ErrorSection = ({
|
|
|
406
406
|
<CapButton
|
|
407
407
|
type="flat"
|
|
408
408
|
className="add-btn"
|
|
409
|
-
onClick={() => window.open(
|
|
409
|
+
onClick={() => window.open(LIQUID_DOC_URL, '_blank')}
|
|
410
410
|
>
|
|
411
411
|
<FormattedMessage {...messages.liquidDoc} />
|
|
412
412
|
<CapIcon size="s" type="launch" />
|
|
@@ -42,6 +42,7 @@ import { useValidation } from './hooks/useValidation';
|
|
|
42
42
|
import {
|
|
43
43
|
HTML_EDITOR_VARIANTS, DEVICE_TYPES, DEFAULT_HTML_CONTENT, TAG, EMBEDDED, DEFAULT, FULL, ALL, SMS, EMAIL,
|
|
44
44
|
BLOCKING_ERROR_RULE_IDS,
|
|
45
|
+
VALIDATION_SEVERITY,
|
|
45
46
|
} from './constants';
|
|
46
47
|
|
|
47
48
|
// Styles
|
|
@@ -50,12 +51,13 @@ import './components/FullscreenModal/_fullscreenModal.scss';
|
|
|
50
51
|
|
|
51
52
|
// Messages
|
|
52
53
|
import messages from './messages';
|
|
54
|
+
import { ISSUE_SOURCES } from './utils/validationConstants';
|
|
53
55
|
|
|
54
56
|
/** Check if an issue is a blocking error (Errors tab). Non-blocking = Warnings. */
|
|
55
57
|
const isBlockingError = (issue) => {
|
|
56
58
|
const { rule, source, severity } = issue || {};
|
|
57
59
|
if (rule === 'liquid-api-validation' || rule === 'standard-api-validation') return true;
|
|
58
|
-
if (source ===
|
|
60
|
+
if (source === ISSUE_SOURCES.LIQUID && severity === VALIDATION_SEVERITY.ERROR) return true;
|
|
59
61
|
if (BLOCKING_ERROR_RULE_IDS.includes(rule)) return true;
|
|
60
62
|
return false;
|
|
61
63
|
};
|
|
@@ -12,17 +12,19 @@
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import PropTypes from 'prop-types';
|
|
14
14
|
import { Layout, Typography } from 'antd';
|
|
15
|
-
import { injectIntl, intlShape } from 'react-intl';
|
|
15
|
+
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
|
16
16
|
|
|
17
17
|
import CapButton from '@capillarytech/cap-ui-library/CapButton';
|
|
18
18
|
import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
|
|
19
19
|
import CapRow from '@capillarytech/cap-ui-library/CapRow';
|
|
20
|
+
import CapTooltipWithInfo from '@capillarytech/cap-ui-library/CapTooltipWithInfo';
|
|
21
|
+
import { FONT_COLOR_01, CAP_SPACE_08, CAP_SPACE_02 } from '@capillarytech/cap-ui-library/styled/variables';
|
|
20
22
|
|
|
21
23
|
// Component imports
|
|
22
24
|
import { useEditorContext } from '../common/EditorContext';
|
|
23
25
|
|
|
24
26
|
// Constants
|
|
25
|
-
import { HTML_EDITOR_VARIANTS } from '../../constants';
|
|
27
|
+
import { HTML_EDITOR_VARIANTS, LIQUID_DOC_URL } from '../../constants';
|
|
26
28
|
|
|
27
29
|
// Styles
|
|
28
30
|
import './_editorToolbar.scss';
|
|
@@ -66,6 +68,29 @@ const EditorToolbar = ({
|
|
|
66
68
|
: intl.formatMessage(messages.htmlEditor)
|
|
67
69
|
}
|
|
68
70
|
</Text>
|
|
71
|
+
<CapTooltipWithInfo
|
|
72
|
+
title={(
|
|
73
|
+
<FormattedMessage
|
|
74
|
+
{...messages.htmlEditorTooltip}
|
|
75
|
+
values={{
|
|
76
|
+
docLink: (
|
|
77
|
+
<a
|
|
78
|
+
href={LIQUID_DOC_URL}
|
|
79
|
+
target="_blank"
|
|
80
|
+
rel="noopener noreferrer"
|
|
81
|
+
>
|
|
82
|
+
<FormattedMessage {...messages.viewDocumentation} />
|
|
83
|
+
</a>
|
|
84
|
+
),
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
)}
|
|
88
|
+
infoIconProps={{
|
|
89
|
+
style: { marginLeft: CAP_SPACE_08, color: FONT_COLOR_01 },
|
|
90
|
+
}}
|
|
91
|
+
autoAdjustOverflow
|
|
92
|
+
placement="top"
|
|
93
|
+
/>
|
|
69
94
|
</CapRow>
|
|
70
95
|
)}
|
|
71
96
|
|
|
@@ -27,6 +27,7 @@ import messages from './messages';
|
|
|
27
27
|
import { BLOCKING_ERROR_RULE_IDS } from '../../constants';
|
|
28
28
|
import './_validationPanel.scss';
|
|
29
29
|
import { SEVERITY } from './constants';
|
|
30
|
+
import { ISSUE_SOURCES } from '../../utils/validationConstants';
|
|
30
31
|
|
|
31
32
|
const { Panel } = Collapse;
|
|
32
33
|
/**
|
|
@@ -72,7 +73,7 @@ const ValidationPanel = ({
|
|
|
72
73
|
return true;
|
|
73
74
|
}
|
|
74
75
|
// Client-side Liquid validation errors are blocking (genuine syntax errors)
|
|
75
|
-
if (source ===
|
|
76
|
+
if (source === ISSUE_SOURCES.LIQUID && severity === SEVERITY.ERROR) {
|
|
76
77
|
return true;
|
|
77
78
|
}
|
|
78
79
|
// Rule Group #1 errors are blocking
|
|
@@ -246,8 +247,8 @@ const ValidationPanel = ({
|
|
|
246
247
|
: messages[key] || { id: `htmlEditor.validation.${key}`, defaultMessage: key };
|
|
247
248
|
|
|
248
249
|
const severity = isSourceGroup
|
|
249
|
-
? (issues.find((i) => i.severity ===
|
|
250
|
-
: issues.find((i) => i.severity ===
|
|
250
|
+
? (issues.find((i) => i.severity === SEVERITY.ERROR) ? SEVERITY.ERROR
|
|
251
|
+
: issues.find((i) => i.severity === SEVERITY.WARNING) ? SEVERITY.WARNING : SEVERITY.INFO)
|
|
251
252
|
: key;
|
|
252
253
|
|
|
253
254
|
return (
|
|
@@ -17,11 +17,12 @@ import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
|
|
|
17
17
|
|
|
18
18
|
// Messages
|
|
19
19
|
import messages from './messages';
|
|
20
|
-
import { BLOCKING_ERROR_RULE_IDS } from '../../constants';
|
|
20
|
+
import { BLOCKING_ERROR_RULE_IDS, VALIDATION_SEVERITY } from '../../constants';
|
|
21
21
|
|
|
22
22
|
// Styles
|
|
23
23
|
import './_validationTabs.scss';
|
|
24
24
|
import { StyledCapTab } from '../../../../v2Containers/MobilePushNew/style';
|
|
25
|
+
import { ISSUE_SOURCES } from '../../utils/validationConstants';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Group issues into Errors (blocking) and Warnings (non-blocking)
|
|
@@ -51,7 +52,7 @@ const isBlockingError = (issue) => {
|
|
|
51
52
|
return true;
|
|
52
53
|
}
|
|
53
54
|
// Client-side Liquid validation errors are blocking (genuine syntax errors)
|
|
54
|
-
if (source ===
|
|
55
|
+
if (source === ISSUE_SOURCES.LIQUID && severity === VALIDATION_SEVERITY.ERROR) {
|
|
55
56
|
return true;
|
|
56
57
|
}
|
|
57
58
|
// Rule Group #1 errors are blocking
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* Centralized constants for the HTML Editor component
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
// Documentation URL for Liquid / HTML editor
|
|
8
|
+
export const LIQUID_DOC_URL = 'https://docs.capillarytech.com/docs/liquid-language-in-messages';
|
|
9
|
+
|
|
7
10
|
// HTML Editor Variants
|
|
8
11
|
export const HTML_EDITOR_VARIANTS = {
|
|
9
12
|
EMAIL: 'email',
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
} from 'react';
|
|
11
11
|
import { validateHTML, extractAndValidateCSS } from '../utils/htmlValidator';
|
|
12
12
|
import { sanitizeHTML, isContentSafe, findUnsafeContent } from '../utils/contentSanitizer';
|
|
13
|
-
import { BLOCKING_ERROR_RULE_IDS } from '../constants';
|
|
13
|
+
import { BLOCKING_ERROR_RULE_IDS, VALIDATION_SEVERITY } from '../constants';
|
|
14
|
+
import { ISSUE_SOURCES } from '../utils/validationConstants';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Custom hook for managing HTML/CSS validation
|
|
@@ -341,25 +342,25 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
341
342
|
const apiLiquidErrors = (apiValidationErrors?.liquidErrors || []).map((errorMessage) => {
|
|
342
343
|
const extractedLine = extractLineNumberFromMessage(errorMessage);
|
|
343
344
|
return {
|
|
344
|
-
type:
|
|
345
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
345
346
|
message: errorMessage,
|
|
346
347
|
line: extractedLine,
|
|
347
348
|
column: null,
|
|
348
349
|
rule: 'liquid-api-validation',
|
|
349
|
-
severity:
|
|
350
|
-
source:
|
|
350
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
351
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
351
352
|
};
|
|
352
353
|
});
|
|
353
354
|
|
|
354
355
|
const apiStandardErrors = (apiValidationErrors?.standardErrors || []).map((errorMessage) => {
|
|
355
356
|
const extractedLine = extractLineNumberFromMessage(errorMessage);
|
|
356
357
|
return {
|
|
357
|
-
type:
|
|
358
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
358
359
|
message: errorMessage,
|
|
359
360
|
line: extractedLine,
|
|
360
361
|
column: null,
|
|
361
362
|
rule: 'standard-api-validation',
|
|
362
|
-
severity:
|
|
363
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
363
364
|
source: 'api-validator',
|
|
364
365
|
};
|
|
365
366
|
});
|
|
@@ -374,19 +375,19 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
374
375
|
? getLineAndColumnFromPosition(contentStr, issue.position)
|
|
375
376
|
: { line: 1, column: 1 };
|
|
376
377
|
return {
|
|
377
|
-
type: isBlocking ?
|
|
378
|
+
type: isBlocking ? VALIDATION_SEVERITY.ERROR : VALIDATION_SEVERITY.WARNING,
|
|
378
379
|
message: `Security issue: ${issue.type}`,
|
|
379
380
|
line,
|
|
380
381
|
column,
|
|
381
382
|
rule: isBlocking ? 'sanitizer.dangerousProtocolDetected' : 'security-violation',
|
|
382
|
-
severity: isBlocking ?
|
|
383
|
+
severity: isBlocking ? VALIDATION_SEVERITY.ERROR : VALIDATION_SEVERITY.WARNING,
|
|
383
384
|
source: 'security',
|
|
384
385
|
};
|
|
385
386
|
});
|
|
386
387
|
|
|
387
388
|
// Sanitization warnings (Rule Group #1 entries have rule set by contentSanitizer)
|
|
388
389
|
const sanitizationAsIssues = (validationState.sanitizationWarnings || []).map((w) => {
|
|
389
|
-
const sev = BLOCKING_ERROR_RULE_IDS.includes(w.rule) ?
|
|
390
|
+
const sev = BLOCKING_ERROR_RULE_IDS.includes(w.rule) ? VALIDATION_SEVERITY.ERROR : VALIDATION_SEVERITY.WARNING;
|
|
390
391
|
return {
|
|
391
392
|
...w,
|
|
392
393
|
severity: sev,
|
|
@@ -451,7 +452,7 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
451
452
|
|
|
452
453
|
const protocolTypes = ['JavaScript Protocol', 'Data URL', 'VBScript Protocol'];
|
|
453
454
|
// Client-side Liquid validation errors are blocking (genuine syntax errors)
|
|
454
|
-
const hasClientSideLiquidErrors = (validationState.htmlErrors || []).some((e) => e.source ===
|
|
455
|
+
const hasClientSideLiquidErrors = (validationState.htmlErrors || []).some((e) => e.source === ISSUE_SOURCES.LIQUID && e.severity === VALIDATION_SEVERITY.ERROR);
|
|
455
456
|
const hasBlockingErrors = (validationState.sanitizationWarnings || []).some((w) => BLOCKING_ERROR_RULE_IDS.includes(w.rule)) || (validationState.securityIssues || []).some((s) => protocolTypes.includes(s?.type)) || hasApiErrors || hasClientSideLiquidErrors;
|
|
456
457
|
|
|
457
458
|
return {
|
|
@@ -328,6 +328,16 @@ export default defineMessages({
|
|
|
328
328
|
},
|
|
329
329
|
},
|
|
330
330
|
|
|
331
|
+
htmlEditorTooltip: {
|
|
332
|
+
id: `${scope}.htmlEditorTooltip`,
|
|
333
|
+
defaultMessage: 'This editor supports standard HTML for emails. Avoid CSS frameworks, external stylesheets, and scripts. {docLink}',
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
viewDocumentation: {
|
|
337
|
+
id: `${scope}.viewDocumentation`,
|
|
338
|
+
defaultMessage: 'View documentation',
|
|
339
|
+
},
|
|
340
|
+
|
|
331
341
|
// HTML Validator messages
|
|
332
342
|
validator: {
|
|
333
343
|
// General validation messages
|
|
@@ -7,6 +7,8 @@ import { html } from '@codemirror/lang-html';
|
|
|
7
7
|
import { syntaxHighlighting, HighlightStyle } from '@codemirror/language';
|
|
8
8
|
import { tags } from '@lezer/highlight';
|
|
9
9
|
import { EditorView } from '@codemirror/view';
|
|
10
|
+
import { VALIDATION_SEVERITY } from '../constants';
|
|
11
|
+
import { ISSUE_SOURCES } from './validationConstants';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Liquid Template Syntax Patterns
|
|
@@ -145,13 +147,13 @@ export class LiquidValidator {
|
|
|
145
147
|
} else {
|
|
146
148
|
// Stray closing brace - no matching opening brace
|
|
147
149
|
this.errors.push({
|
|
148
|
-
type:
|
|
150
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
149
151
|
message: 'Stray closing }} without matching opening {{',
|
|
150
152
|
line: this.getLineNumber(html, position),
|
|
151
153
|
column: 1,
|
|
152
154
|
rule: 'liquid-stray-closing-output',
|
|
153
|
-
severity:
|
|
154
|
-
source:
|
|
155
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
156
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
155
157
|
});
|
|
156
158
|
}
|
|
157
159
|
}
|
|
@@ -162,13 +164,13 @@ export class LiquidValidator {
|
|
|
162
164
|
// Report each unclosed opening brace
|
|
163
165
|
stack.forEach((position) => {
|
|
164
166
|
this.errors.push({
|
|
165
|
-
type:
|
|
167
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
166
168
|
message: 'unclosed Liquid output tag - missing }}',
|
|
167
169
|
line: this.getLineNumber(html, position),
|
|
168
170
|
column: 1,
|
|
169
171
|
rule: 'liquid-unclosed-output',
|
|
170
|
-
severity:
|
|
171
|
-
source:
|
|
172
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
173
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
172
174
|
});
|
|
173
175
|
});
|
|
174
176
|
}
|
|
@@ -197,13 +199,13 @@ export class LiquidValidator {
|
|
|
197
199
|
if (openTags.length > closeTags.length) {
|
|
198
200
|
const unmatchedCount = openTags.length - closeTags.length;
|
|
199
201
|
this.errors.push({
|
|
200
|
-
type:
|
|
202
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
201
203
|
message: `${unmatchedCount} unclosed Liquid logic tag(s) - missing %}`,
|
|
202
204
|
line: this.getLineNumber(html, openTags[openTags.length - 1]),
|
|
203
205
|
column: 1,
|
|
204
206
|
rule: 'liquid-unclosed-logic',
|
|
205
|
-
severity:
|
|
206
|
-
source:
|
|
207
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
208
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
207
209
|
});
|
|
208
210
|
}
|
|
209
211
|
}
|
|
@@ -218,13 +220,13 @@ export class LiquidValidator {
|
|
|
218
220
|
if (nestedOutput) {
|
|
219
221
|
nestedOutput.forEach((match) => {
|
|
220
222
|
this.errors.push({
|
|
221
|
-
type:
|
|
223
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
222
224
|
message: `Nested braces in Liquid output tag: ${match}`,
|
|
223
225
|
line: this.getLineNumber(html, html.indexOf(match)),
|
|
224
226
|
column: 1,
|
|
225
227
|
rule: 'liquid-nested-braces',
|
|
226
|
-
severity:
|
|
227
|
-
source:
|
|
228
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
229
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
228
230
|
});
|
|
229
231
|
});
|
|
230
232
|
}
|
|
@@ -235,13 +237,13 @@ export class LiquidValidator {
|
|
|
235
237
|
if (nestedLogic) {
|
|
236
238
|
nestedLogic.forEach((match) => {
|
|
237
239
|
this.errors.push({
|
|
238
|
-
type:
|
|
240
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
239
241
|
message: `Nested braces in Liquid logic tag: ${match}`,
|
|
240
242
|
line: this.getLineNumber(html, html.indexOf(match)),
|
|
241
243
|
column: 1,
|
|
242
244
|
rule: 'liquid-nested-braces',
|
|
243
|
-
severity:
|
|
244
|
-
source:
|
|
245
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
246
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
245
247
|
});
|
|
246
248
|
});
|
|
247
249
|
}
|
|
@@ -302,23 +304,23 @@ export class LiquidValidator {
|
|
|
302
304
|
|
|
303
305
|
if (!lastOpening) {
|
|
304
306
|
this.errors.push({
|
|
305
|
-
type:
|
|
307
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
306
308
|
message: `Unexpected closing tag: {% ${keyword} %}`,
|
|
307
309
|
line: tag.line,
|
|
308
310
|
column: 1,
|
|
309
311
|
rule: 'liquid-unexpected-closing',
|
|
310
|
-
severity:
|
|
311
|
-
source:
|
|
312
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
313
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
312
314
|
});
|
|
313
315
|
} else if (lastOpening.keyword !== expectedOpening) {
|
|
314
316
|
this.errors.push({
|
|
315
|
-
type:
|
|
317
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
316
318
|
message: `Mismatched Liquid tags: {% ${lastOpening.keyword} %} ... {% ${keyword} %}`,
|
|
317
319
|
line: tag.line,
|
|
318
320
|
column: 1,
|
|
319
321
|
rule: 'liquid-mismatched-tags',
|
|
320
|
-
severity:
|
|
321
|
-
source:
|
|
322
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
323
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
322
324
|
});
|
|
323
325
|
}
|
|
324
326
|
}
|
|
@@ -329,13 +331,13 @@ export class LiquidValidator {
|
|
|
329
331
|
stack.forEach(({ keyword, tag }) => {
|
|
330
332
|
const expectedClosing = pairs[keyword];
|
|
331
333
|
const error = {
|
|
332
|
-
type:
|
|
334
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
333
335
|
message: `Unclosed Liquid tag: {% ${keyword} %} - missing {% ${expectedClosing} %}`,
|
|
334
336
|
line: tag.line,
|
|
335
337
|
column: 1,
|
|
336
338
|
rule: 'liquid-unclosed-tag',
|
|
337
|
-
severity:
|
|
338
|
-
source:
|
|
339
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
340
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
339
341
|
};
|
|
340
342
|
this.errors.push(error);
|
|
341
343
|
});
|
|
@@ -344,13 +346,13 @@ export class LiquidValidator {
|
|
|
344
346
|
// Check for unclosed opening tags
|
|
345
347
|
stack.forEach((unclosed) => {
|
|
346
348
|
this.errors.push({
|
|
347
|
-
type:
|
|
349
|
+
type: VALIDATION_SEVERITY.ERROR,
|
|
348
350
|
message: `Unclosed Liquid tag: {% ${unclosed.keyword} %}`,
|
|
349
351
|
line: unclosed.tag.line,
|
|
350
352
|
column: 1,
|
|
351
353
|
rule: 'liquid-unclosed-tag',
|
|
352
|
-
severity:
|
|
353
|
-
source:
|
|
354
|
+
severity: VALIDATION_SEVERITY.ERROR,
|
|
355
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
354
356
|
});
|
|
355
357
|
});
|
|
356
358
|
}
|
|
@@ -364,13 +366,13 @@ export class LiquidValidator {
|
|
|
364
366
|
if (malformedFilters) {
|
|
365
367
|
malformedFilters.forEach((match) => {
|
|
366
368
|
this.warnings.push({
|
|
367
|
-
type:
|
|
369
|
+
type: VALIDATION_SEVERITY.WARNING,
|
|
368
370
|
message: `Malformed Liquid filter: ${match.trim()}`,
|
|
369
371
|
line: this.getLineNumber(html, html.indexOf(match)),
|
|
370
372
|
column: 1,
|
|
371
373
|
rule: 'liquid-malformed-filter',
|
|
372
|
-
severity:
|
|
373
|
-
source:
|
|
374
|
+
severity: VALIDATION_SEVERITY.WARNING,
|
|
375
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
374
376
|
});
|
|
375
377
|
});
|
|
376
378
|
}
|
|
@@ -401,13 +403,13 @@ export class LiquidValidator {
|
|
|
401
403
|
// Only show info for truly custom/unknown filters
|
|
402
404
|
// Standard Liquid filters are now included in commonFilters list
|
|
403
405
|
this.info.push({
|
|
404
|
-
type:
|
|
406
|
+
type: VALIDATION_SEVERITY.INFO,
|
|
405
407
|
message: `Using filter: ${filterName}`,
|
|
406
408
|
line: this.getLineNumber(html, filterMatch.index),
|
|
407
409
|
column: 1,
|
|
408
410
|
rule: 'liquid-filter-usage',
|
|
409
|
-
severity:
|
|
410
|
-
source:
|
|
411
|
+
severity: VALIDATION_SEVERITY.INFO,
|
|
412
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
411
413
|
});
|
|
412
414
|
}
|
|
413
415
|
}
|
|
@@ -422,13 +424,13 @@ export class LiquidValidator {
|
|
|
422
424
|
if (suspiciousVariables) {
|
|
423
425
|
suspiciousVariables.forEach((match) => {
|
|
424
426
|
this.warnings.push({
|
|
425
|
-
type:
|
|
427
|
+
type: VALIDATION_SEVERITY.WARNING,
|
|
426
428
|
message: `Potentially undefined variable: ${match}`,
|
|
427
429
|
line: this.getLineNumber(html, html.indexOf(match)),
|
|
428
430
|
column: 1,
|
|
429
431
|
rule: 'liquid-undefined-variable',
|
|
430
|
-
severity:
|
|
431
|
-
source:
|
|
432
|
+
severity: VALIDATION_SEVERITY.WARNING,
|
|
433
|
+
source: ISSUE_SOURCES.LIQUID,
|
|
432
434
|
});
|
|
433
435
|
});
|
|
434
436
|
}
|
|
@@ -16,6 +16,7 @@ import { INAPP } from '../../v2Containers/App/constants';
|
|
|
16
16
|
import { ANDROID, IOS } from '../../v2Containers/InApp/constants';
|
|
17
17
|
import { getCtaObject } from '../../v2Containers/InApp/utils';
|
|
18
18
|
import { CAROUSEL, VIDEO } from '../../v2Containers/MobilePushNew/constants';
|
|
19
|
+
import { DEVICE_TYPES, IPHONE } from './constants';
|
|
19
20
|
|
|
20
21
|
class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
|
21
22
|
constructor(props) {
|
|
@@ -57,7 +58,7 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
57
58
|
const isBeeFreeTemplate = get(androidContent, 'isBEEeditor') || get(iosContent, 'isBEEeditor');
|
|
58
59
|
if (isBeeFreeTemplate) {
|
|
59
60
|
// Normalize device to 'android' or 'ios' for comparison
|
|
60
|
-
const normalizedDevice = device ===
|
|
61
|
+
const normalizedDevice = device === IPHONE ? DEVICE_TYPES.IOS : device?.toLowerCase();
|
|
61
62
|
const isAndroid = normalizedDevice === ANDROID.toLowerCase();
|
|
62
63
|
content = {
|
|
63
64
|
inAppPreviewContent: isAndroid ? androidContent?.beeHtml : iosContent?.beeHtml,
|
|
@@ -78,7 +79,7 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
78
79
|
ctaData: getCtaObject(iosContent?.expandableDetails?.ctas),
|
|
79
80
|
};
|
|
80
81
|
// Normalize device to 'android' or 'ios' for comparison
|
|
81
|
-
const normalizedDevice = device ===
|
|
82
|
+
const normalizedDevice = device === IPHONE ? DEVICE_TYPES.IOS : device?.toLowerCase();
|
|
82
83
|
const isAndroid = normalizedDevice === ANDROID.toLowerCase();
|
|
83
84
|
content = {
|
|
84
85
|
inAppPreviewContent: isAndroid ? androidPreviewContent : iosPreviewContent,
|
|
@@ -149,7 +150,7 @@ class MobilePushPreviewV2 extends React.Component { // eslint-disable-line react
|
|
|
149
150
|
|
|
150
151
|
getPreview(device) {
|
|
151
152
|
// Normalize device to 'android' or 'ios' for comparison
|
|
152
|
-
const normalizedDevice = device ===
|
|
153
|
+
const normalizedDevice = device === IPHONE ? DEVICE_TYPES.IOS : device?.toLowerCase();
|
|
153
154
|
const deviceParam = normalizedDevice === ANDROID.toLowerCase() ? ANDROID : IOS;
|
|
154
155
|
return (
|
|
155
156
|
<TemplatePreview
|