@useinsider/guido 3.17.0-beta.e6704da → 3.17.0-beta.ea65303
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/README.md +1 -1
- package/dist/@types/config/schemas.js +31 -35
- package/dist/components/Guido.vue.js +5 -5
- package/dist/components/Guido.vue2.js +77 -77
- package/dist/components/organisms/AutoSaveController.vue2.js +9 -8
- package/dist/components/organisms/header/EditorActions.vue.js +2 -2
- package/dist/components/organisms/header/EditorActions.vue2.js +74 -43
- package/dist/components/organisms/header/LeftSlot.vue.js +5 -5
- package/dist/components/organisms/header/LeftSlot.vue2.js +16 -12
- package/dist/components/organisms/validation/ValidationErrorDrawer.vue.js +20 -0
- package/dist/components/organisms/validation/ValidationErrorDrawer.vue2.js +48 -0
- package/dist/components/wrappers/WpDrawer.vue.js +9 -7
- package/dist/components/wrappers/WpDrawer.vue2.js +1 -1
- package/dist/composables/useCustomInterfaceAppearance.js +16 -19
- package/dist/composables/useHtmlCompiler.js +37 -26
- package/dist/composables/useHtmlValidator.js +2 -0
- package/dist/composables/useRecommendation.js +34 -41
- package/dist/composables/useSave.js +84 -41
- package/dist/composables/useSaveValidation.js +279 -0
- package/dist/composables/useSaveValidationRollout.js +9 -0
- package/dist/composables/validators/useCouponBlockValidator.js +24 -21
- package/dist/composables/validators/useUnsubscribeBlockValidator.js +34 -27
- package/dist/config/migrator/recommendationMigrator.js +4 -6
- package/dist/enums/academy.js +1 -2
- package/dist/enums/date.js +3 -4
- package/dist/enums/extensions/recommendationBlock.js +23 -25
- package/dist/enums/save-validation.js +4 -0
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +11 -13
- package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +95 -96
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +154 -156
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +82 -223
- package/dist/extensions/Blocks/common-control.js +19 -22
- package/dist/guido.css +1 -1
- package/dist/services/recommendationApi.js +29 -78
- package/dist/src/@types/config/schemas.d.ts +4 -12
- package/dist/src/@types/save-validation.d.ts +19 -0
- package/dist/src/components/Guido.vue.d.ts +17 -1
- package/dist/src/components/organisms/header/EditorActions.vue.d.ts +17 -1
- package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +17 -1
- package/dist/src/components/organisms/header/RightSlot.vue.d.ts +17 -1
- package/dist/src/components/organisms/{extensions/recommendation/AssignStrategyDrawer.vue.d.ts → validation/ValidationErrorDrawer.vue.d.ts} +0 -1
- package/dist/src/components/wrappers/WpDrawer.vue.d.ts +4 -3
- package/dist/src/composables/useConfig.d.ts +2 -2
- package/dist/src/composables/useHtmlValidator.d.ts +21 -0
- package/dist/src/composables/useRecommendation.d.ts +0 -1
- package/dist/src/composables/useSave.d.ts +6 -1
- package/dist/src/composables/useSaveValidation.d.ts +6 -0
- package/dist/src/composables/useSaveValidationRollout.d.ts +3 -0
- package/dist/src/composables/validators/useCouponBlockValidator.d.ts +3 -0
- package/dist/src/composables/validators/useUnsubscribeBlockValidator.d.ts +10 -0
- package/dist/src/enums/academy.d.ts +0 -1
- package/dist/src/enums/extensions/recommendationBlock.d.ts +0 -2
- package/dist/src/enums/save-validation.d.ts +27 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +3 -14
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +15 -214
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +0 -6
- package/dist/src/extensions/Blocks/common-control.d.ts +1 -4
- package/dist/src/services/recommendationApi.d.ts +1 -4
- package/dist/src/stores/config.d.ts +30 -18
- package/dist/src/stores/save-validation.d.ts +22 -0
- package/dist/src/utils/templatePreparation.d.ts +30 -0
- package/dist/stores/config.js +39 -22
- package/dist/stores/save-validation.js +30 -0
- package/dist/utils/dateUtil.js +10 -23
- package/dist/utils/templatePreparation.js +50 -50
- package/package.json +1 -2
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +0 -18
- package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +0 -70
- package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue.js +0 -20
- package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue2.js +0 -55
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +0 -141
- package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBox.vue.d.ts +0 -24
- package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +0 -29
- package/dist/src/mock/api/recommendation-strategies.d.ts +0 -43
- package/dist/static/styles/components/recommendation-strategy.css.js +0 -171
|
@@ -1,101 +1,52 @@
|
|
|
1
|
-
import { useHttp as
|
|
2
|
-
import {
|
|
3
|
-
const R =
|
|
4
|
-
(
|
|
5
|
-
attributeName:
|
|
6
|
-
attributeJs:
|
|
7
|
-
attributeType:
|
|
8
|
-
type:
|
|
9
|
-
displayName:
|
|
10
|
-
isFilterable:
|
|
11
|
-
},
|
|
1
|
+
import { useHttp as d } from "../composables/useHttp.js";
|
|
2
|
+
import { QUERY_PARAMS as l, URLS as u } from "../enums/extensions/recommendationBlock.js";
|
|
3
|
+
const R = (o) => o.reduce(
|
|
4
|
+
(a, t, s) => (a[s] = {
|
|
5
|
+
attributeName: t.attributeName,
|
|
6
|
+
attributeJs: t.attributeJs,
|
|
7
|
+
attributeType: t.attributeType,
|
|
8
|
+
type: t.type,
|
|
9
|
+
displayName: t.displayName,
|
|
10
|
+
isFilterable: t.isFilterable
|
|
11
|
+
}, a),
|
|
12
12
|
{}
|
|
13
|
-
),
|
|
14
|
-
const { get:
|
|
13
|
+
), f = () => {
|
|
14
|
+
const { get: o } = d(), { get: a } = d({ headers: {} }), t = "6KcLM9TwheVB1mgK";
|
|
15
15
|
return {
|
|
16
16
|
fetchRecommendationCreateData: async () => {
|
|
17
17
|
try {
|
|
18
|
-
return (await
|
|
18
|
+
return (await o("/newsletter/recommendations/create-data")).data;
|
|
19
19
|
} catch (e) {
|
|
20
20
|
throw console.error("fetchUserModalState error:", e), e;
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
fetchRecommendationFilters: async () => {
|
|
24
24
|
try {
|
|
25
|
-
const { data: e } = await
|
|
26
|
-
|
|
27
|
-
),
|
|
28
|
-
return
|
|
25
|
+
const { data: e } = await o(
|
|
26
|
+
u.PRODUCT_ATTRIBUTES_PATH
|
|
27
|
+
), n = Array.isArray(e) ? e : (e == null ? void 0 : e.data) ?? [];
|
|
28
|
+
return R(n);
|
|
29
29
|
} catch (e) {
|
|
30
30
|
throw console.error("fetchRecommendationFilters error:", e), e;
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
fetchRecommendationProducts: async (e,
|
|
34
|
-
var
|
|
33
|
+
fetchRecommendationProducts: async (e, n) => {
|
|
34
|
+
var i;
|
|
35
35
|
try {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
console.debug("🏁 Recommendation API Query:",
|
|
40
|
-
const
|
|
41
|
-
`${
|
|
36
|
+
const r = new URLSearchParams(Object.entries(n));
|
|
37
|
+
r.set(l.CLIENT_ID, t);
|
|
38
|
+
const m = decodeURIComponent(r.toString());
|
|
39
|
+
console.debug("🏁 Recommendation API Query:", m);
|
|
40
|
+
const c = await a(
|
|
41
|
+
`${u.RECOMMENDATION_API_URL}/v2/${e}?${m}`
|
|
42
42
|
);
|
|
43
|
-
return ((
|
|
44
|
-
} catch (o) {
|
|
45
|
-
throw console.error("fetchRecommendationProducts error:", o), o;
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
fetchRecommendationProductsByUrl: async (e) => {
|
|
49
|
-
var t;
|
|
50
|
-
try {
|
|
51
|
-
const r = new RegExp(`[?&]${h.CLIENT_ID}=`).test(e), o = e.includes("?") ? "&" : "?", c = r ? e : `${e}${o}${h.CLIENT_ID}=${d}`, n = await a(
|
|
52
|
-
c
|
|
53
|
-
);
|
|
54
|
-
return ((t = n == null ? void 0 : n.data) == null ? void 0 : t.data) ?? [];
|
|
43
|
+
return ((i = c == null ? void 0 : c.data) == null ? void 0 : i.data) ?? [];
|
|
55
44
|
} catch (r) {
|
|
56
|
-
throw console.error("
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
fetchRecommendationStrategies: async () => {
|
|
60
|
-
try {
|
|
61
|
-
const e = /* @__PURE__ */ new Map();
|
|
62
|
-
let t = 1;
|
|
63
|
-
for (; ; ) {
|
|
64
|
-
const { data: r } = await s(
|
|
65
|
-
`${m.RECOMMENDATION_STRATEGIES_PATH}?filters=${encodeURIComponent(l)}&per_page=${R}&page=${t}`
|
|
66
|
-
), o = Array.isArray(r) ? r : (r == null ? void 0 : r.data) ?? [], c = e.size;
|
|
67
|
-
if (o.forEach((n) => e.set(n.strategy_id, n)), o.length < R || e.size === c)
|
|
68
|
-
break;
|
|
69
|
-
t += 1;
|
|
70
|
-
}
|
|
71
|
-
return [...e.values()];
|
|
72
|
-
} catch (e) {
|
|
73
|
-
throw console.error("fetchRecommendationStrategies error:", e), e;
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
generateStrategyEndpoint: async (e) => {
|
|
77
|
-
try {
|
|
78
|
-
const { data: t } = await i(
|
|
79
|
-
`${m.RECOMMENDATION_STRATEGIES_PATH}/endpoint-generate`,
|
|
80
|
-
{
|
|
81
|
-
// Email designs have no campaign yet; backend only needs it
|
|
82
|
-
// for previewer flows.
|
|
83
|
-
campaignId: 0,
|
|
84
|
-
pageTypes: [],
|
|
85
|
-
isPreviewer: !1,
|
|
86
|
-
strategy: e,
|
|
87
|
-
userId: ""
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
if (!t || typeof t != "object" || !("full_path" in t || "data" in t))
|
|
91
|
-
throw new Error("Unexpected endpoint-generate response shape");
|
|
92
|
-
return "full_path" in t ? t : t.data;
|
|
93
|
-
} catch (t) {
|
|
94
|
-
throw console.error("generateStrategyEndpoint error:", t), t;
|
|
45
|
+
throw console.error("fetchRecommendationProducts error:", r), r;
|
|
95
46
|
}
|
|
96
47
|
}
|
|
97
48
|
};
|
|
98
49
|
};
|
|
99
50
|
export {
|
|
100
|
-
|
|
51
|
+
f as useRecommendationApi
|
|
101
52
|
};
|
|
@@ -395,12 +395,8 @@ export declare const FeaturesSchema: v.ObjectSchema<{
|
|
|
395
395
|
readonly allowlistEnabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
|
|
396
396
|
/** Enable persistent link tracking-id assignment for the click heatmap (opt-in) */
|
|
397
397
|
readonly linkTrackingIds: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
|
|
398
|
-
/**
|
|
399
|
-
|
|
400
|
-
* per-block algorithm settings. Hides Algorithm, Filters, Shuffle and Number of Products
|
|
401
|
-
* (they live on the strategy) and adds the Assign Strategy flow.
|
|
402
|
-
*/
|
|
403
|
-
readonly reusableRecommendationStrategy: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
|
|
398
|
+
/** Allow persisting a template that still has validation errors (drawer "Save and Continue" soft-save). Host sets false for transactional + unsubscribe. */
|
|
399
|
+
readonly allowSaveWithErrors: v.OptionalSchema<v.BooleanSchema<undefined>, true>;
|
|
404
400
|
}, undefined>;
|
|
405
401
|
/**
|
|
406
402
|
* Default block types available in Stripo
|
|
@@ -800,12 +796,8 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
|
|
|
800
796
|
readonly allowlistEnabled: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
|
|
801
797
|
/** Enable persistent link tracking-id assignment for the click heatmap (opt-in) */
|
|
802
798
|
readonly linkTrackingIds: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
|
|
803
|
-
/**
|
|
804
|
-
|
|
805
|
-
* per-block algorithm settings. Hides Algorithm, Filters, Shuffle and Number of Products
|
|
806
|
-
* (they live on the strategy) and adds the Assign Strategy flow.
|
|
807
|
-
*/
|
|
808
|
-
readonly reusableRecommendationStrategy: v.OptionalSchema<v.BooleanSchema<undefined>, false>;
|
|
799
|
+
/** Allow persisting a template that still has validation errors (drawer "Save and Continue" soft-save). Host sets false for transactional + unsubscribe. */
|
|
800
|
+
readonly allowSaveWithErrors: v.OptionalSchema<v.BooleanSchema<undefined>, true>;
|
|
809
801
|
}, undefined>, {}>;
|
|
810
802
|
/** Block configuration */
|
|
811
803
|
readonly blocks: v.OptionalSchema<v.ObjectSchema<{
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SaveValidationRule } from '@@/Enums/save-validation';
|
|
2
|
+
import type { ToasterTypeOptions } from '@@/Enums/toaster';
|
|
3
|
+
/** Which action triggered the validation run. Drives telemetry only in v1. */
|
|
4
|
+
export type SaveValidationIntent = 'save' | 'back' | 'test';
|
|
5
|
+
/**
|
|
6
|
+
* A single validation failure instance, one per drawer row. Names avoid the
|
|
7
|
+
* public `ValidationError` (config validation) collision — NOT exported from
|
|
8
|
+
* library.ts.
|
|
9
|
+
*/
|
|
10
|
+
export interface SaveValidationError {
|
|
11
|
+
/** Stable discriminator for tests and de-duplication. */
|
|
12
|
+
rule: SaveValidationRule;
|
|
13
|
+
/** Final translated string — trans() is applied at collect time. */
|
|
14
|
+
message: string;
|
|
15
|
+
/** Raw user content (field name / tag / src) — not i18n. */
|
|
16
|
+
detail?: string;
|
|
17
|
+
/** Mirrors the legacy toaster severity. Kept for the discriminator/tests; the drawer renders a uniform icon and never reads it. */
|
|
18
|
+
type: ToasterTypeOptions;
|
|
19
|
+
}
|
|
@@ -15,7 +15,23 @@ declare const _default: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_T
|
|
|
15
15
|
close: () => void;
|
|
16
16
|
};
|
|
17
17
|
hasChanges: import("vue").ComputedRef<boolean>;
|
|
18
|
-
saveSilent: () => Promise<
|
|
18
|
+
saveSilent: () => Promise<{
|
|
19
|
+
dynamicContentList: import("@@/Types/generic").DynamicContent[];
|
|
20
|
+
compiledHtml: string;
|
|
21
|
+
rawHtml: string;
|
|
22
|
+
css: string;
|
|
23
|
+
ampHtml: string;
|
|
24
|
+
ampErrors: string[];
|
|
25
|
+
modules: number[];
|
|
26
|
+
recommendation: {
|
|
27
|
+
campaignUrls: Record<string, string>;
|
|
28
|
+
configs: Record<string, string>;
|
|
29
|
+
};
|
|
30
|
+
unsubscribe: {
|
|
31
|
+
status: boolean;
|
|
32
|
+
config: number[];
|
|
33
|
+
};
|
|
34
|
+
} | undefined> | undefined;
|
|
19
35
|
setLoading: (value: boolean) => void;
|
|
20
36
|
}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {
|
|
21
37
|
"dynamic-content:open": (detail: {
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
-
handleSave: (isSilent: boolean) => Promise<
|
|
2
|
+
handleSave: (isSilent: boolean) => Promise<{
|
|
3
|
+
dynamicContentList: import("../../../@types/generic.js").DynamicContent[];
|
|
4
|
+
compiledHtml: string;
|
|
5
|
+
rawHtml: string;
|
|
6
|
+
css: string;
|
|
7
|
+
ampHtml: string;
|
|
8
|
+
ampErrors: string[];
|
|
9
|
+
modules: number[];
|
|
10
|
+
recommendation: {
|
|
11
|
+
campaignUrls: Record<string, string>;
|
|
12
|
+
configs: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
unsubscribe: {
|
|
15
|
+
status: boolean;
|
|
16
|
+
config: number[];
|
|
17
|
+
};
|
|
18
|
+
} | undefined> | undefined;
|
|
3
19
|
}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
|
|
4
20
|
export default _default;
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
-
handleSave: (isSilent: boolean) => Promise<
|
|
2
|
+
handleSave: (isSilent: boolean) => Promise<{
|
|
3
|
+
dynamicContentList: import("../../../@types/generic.js").DynamicContent[];
|
|
4
|
+
compiledHtml: string;
|
|
5
|
+
rawHtml: string;
|
|
6
|
+
css: string;
|
|
7
|
+
ampHtml: string;
|
|
8
|
+
ampErrors: string[];
|
|
9
|
+
modules: number[];
|
|
10
|
+
recommendation: {
|
|
11
|
+
campaignUrls: Record<string, string>;
|
|
12
|
+
configs: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
unsubscribe: {
|
|
15
|
+
status: boolean;
|
|
16
|
+
config: number[];
|
|
17
|
+
};
|
|
18
|
+
} | undefined> | undefined;
|
|
3
19
|
}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
|
|
4
20
|
export default _default;
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
-
handleSave: (isSilent: boolean) => Promise<
|
|
2
|
+
handleSave: (isSilent: boolean) => Promise<{
|
|
3
|
+
dynamicContentList: import("../../../@types/generic.js").DynamicContent[];
|
|
4
|
+
compiledHtml: string;
|
|
5
|
+
rawHtml: string;
|
|
6
|
+
css: string;
|
|
7
|
+
ampHtml: string;
|
|
8
|
+
ampErrors: string[];
|
|
9
|
+
modules: number[];
|
|
10
|
+
recommendation: {
|
|
11
|
+
campaignUrls: Record<string, string>;
|
|
12
|
+
configs: Record<string, string>;
|
|
13
|
+
};
|
|
14
|
+
unsubscribe: {
|
|
15
|
+
status: boolean;
|
|
16
|
+
config: number[];
|
|
17
|
+
};
|
|
18
|
+
} | undefined> | undefined;
|
|
3
19
|
}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
|
|
4
20
|
export default _default;
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import '@useinsider/design-system-organisms/style';
|
|
2
1
|
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue/types/v3-component-options.js").ComponentOptionsMixin, import("vue/types/v3-component-options.js").ComponentOptionsMixin, {}, string, Readonly<import("vue").ExtractPropTypes<{}>>, {}>;
|
|
3
2
|
export default _default;
|
|
@@ -10,11 +10,11 @@ interface Props {
|
|
|
10
10
|
status: boolean;
|
|
11
11
|
titleText: string;
|
|
12
12
|
}
|
|
13
|
-
declare var
|
|
13
|
+
declare var __VLS_13: {}, __VLS_15: {};
|
|
14
14
|
type __VLS_Slots = {} & {
|
|
15
|
-
headerBottomSlot?: (props: typeof
|
|
15
|
+
headerBottomSlot?: (props: typeof __VLS_13) => any;
|
|
16
16
|
} & {
|
|
17
|
-
default?: (props: typeof
|
|
17
|
+
default?: (props: typeof __VLS_15) => any;
|
|
18
18
|
};
|
|
19
19
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_WithDefaults<__VLS_TypePropsToOption<Props>, {
|
|
20
20
|
className: string;
|
|
@@ -26,6 +26,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_WithDefaults<
|
|
|
26
26
|
cancelOrBackButtonEvent: () => void;
|
|
27
27
|
onCloseEvent: () => void;
|
|
28
28
|
primaryButtonEvent: () => void;
|
|
29
|
+
secondaryButtonEvent: () => void;
|
|
29
30
|
}, string, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<Props>, {
|
|
30
31
|
className: string;
|
|
31
32
|
size: string;
|
|
@@ -99,7 +99,7 @@ export declare const useConfig: () => {
|
|
|
99
99
|
autosave: boolean;
|
|
100
100
|
allowlistEnabled: boolean;
|
|
101
101
|
linkTrackingIds: boolean;
|
|
102
|
-
|
|
102
|
+
allowSaveWithErrors: boolean;
|
|
103
103
|
};
|
|
104
104
|
blocks: {
|
|
105
105
|
excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
|
|
@@ -234,7 +234,7 @@ export declare const useConfig: () => {
|
|
|
234
234
|
autosave: boolean;
|
|
235
235
|
allowlistEnabled: boolean;
|
|
236
236
|
linkTrackingIds: boolean;
|
|
237
|
-
|
|
237
|
+
allowSaveWithErrors: boolean;
|
|
238
238
|
} | null>;
|
|
239
239
|
blocks: import("vue").ComputedRef<{
|
|
240
240
|
excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { DynamicContent } from '@@/Types/generic';
|
|
2
2
|
import type { FiltersResponse } from '@@/Types/recommendation';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts recommendation block IDs directly from the HTML by parsing
|
|
5
|
+
* the recommendation-id attribute on block elements.
|
|
6
|
+
* This avoids depending on store state which may not be populated
|
|
7
|
+
* when the settings panel hasn't been opened yet (e.g., saved templates).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getRecommendationBlockIds(html: string): string[];
|
|
3
10
|
/**
|
|
4
11
|
* Parses a `{{recoId_index_attributeName}}` variable (already stripped of the
|
|
5
12
|
* braces/whitespace) into its recommendation id and attribute name. Returns
|
|
@@ -27,6 +34,20 @@ export declare function buildPartnerAttributeNameSet(filterList: FiltersResponse
|
|
|
27
34
|
* before, so flagging it would false-positive on merge tags like `{{user.name}}`.
|
|
28
35
|
*/
|
|
29
36
|
export declare function findInvalidCustomFields(html: string, validCustomFields: string[], recommendationBlockIds: string[], ignoredIds: Set<string>, ignoredAttributeNames: Set<string> | null): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Returns the invalid `{{ ... }}` dynamic-content tags found in the HTML.
|
|
39
|
+
*
|
|
40
|
+
* A tag's variable name is the part before the first `|` (everything after it is the fallback).
|
|
41
|
+
* Surrounding whitespace is always allowed (trimmed). A tag is valid only when the variable name
|
|
42
|
+
* is an allowed system token, or it is a clean identifier (`[A-Za-z0-9_.]`) and — when a `|` is
|
|
43
|
+
* present — the fallback after it is not empty. Otherwise the tag is invalid (e.g.
|
|
44
|
+
* `{{Api Response: OA1 Main Item Url}}` — spaces/`:` — or `{{bounce|}}` — empty fallback).
|
|
45
|
+
*
|
|
46
|
+
* `data-*` block-config attribute values are excluded from the scan: blocks such as Items/cart
|
|
47
|
+
* store product merge tags (`data-product_button_link="{{Abandoned Cart Item (1) Url}}"`) that the
|
|
48
|
+
* backend resolves through its own pipeline, so they must not be treated as user-authored tags.
|
|
49
|
+
*/
|
|
50
|
+
export declare function getInvalidDynamicContentTags(html: string): string[];
|
|
30
51
|
export declare const useHtmlValidator: () => {
|
|
31
52
|
validateHtml: (html: string, customFields: DynamicContent[], isOnSaveValidation?: boolean) => Promise<boolean>;
|
|
32
53
|
};
|
|
@@ -18,7 +18,6 @@ export declare const useRecommendation: () => {
|
|
|
18
18
|
getRecommendationCampaignData: (id: string) => CampaignData;
|
|
19
19
|
buildCampaignUrl: (campaignId: string, overrides?: {
|
|
20
20
|
strategy: string;
|
|
21
|
-
strategyId: string;
|
|
22
21
|
language: string;
|
|
23
22
|
currencyCode: string;
|
|
24
23
|
size: string;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { SavedTemplateDetails } from '@@/Types/stripo';
|
|
2
|
+
type SaveDetails = Omit<SavedTemplateDetails, 'metadata' | 'silent'>;
|
|
3
|
+
type SaveResult = SaveDetails | undefined;
|
|
2
4
|
export declare const useSave: () => {
|
|
3
|
-
save: (suppressEmit?: boolean, silent?: boolean) => Promise<
|
|
5
|
+
save: (suppressEmit?: boolean, silent?: boolean) => Promise<SaveResult>;
|
|
6
|
+
saveWithErrors: () => Promise<SaveResult>;
|
|
7
|
+
saveRawOnly: () => Promise<SaveResult>;
|
|
4
8
|
};
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DynamicContent } from '@@/Types/generic';
|
|
2
|
+
import type { SaveValidationError } from '@@/Types/save-validation';
|
|
3
|
+
export declare const useSaveValidation: () => {
|
|
4
|
+
collectSaveValidationErrors: (compiledHtml: string, dynamicContentList: DynamicContent[]) => Promise<SaveValidationError[]>;
|
|
5
|
+
validateCurrentTemplate: () => Promise<SaveValidationError[]>;
|
|
6
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export declare const COUPON_TAG_MODIFIED_KEY = "newsletter.coupon-tag-modified";
|
|
2
|
+
/** Pure core: the tag text of every coupon block whose code was modified. */
|
|
3
|
+
export declare function findInvalidCouponBlocks(html: string): string[];
|
|
1
4
|
export declare const useCouponBlockValidator: () => {
|
|
2
5
|
validateCouponBlockTags: (html: string) => boolean;
|
|
3
6
|
};
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
declare const SINGLETON_BLOCK_RULES: {
|
|
2
|
+
pageType: number;
|
|
3
|
+
messageKey: string;
|
|
4
|
+
}[];
|
|
5
|
+
export declare const EMPTY_BLOCK_KEY = "unsubscription-preference.select-page-to-continue";
|
|
6
|
+
/** Pure core: the singleton rules whose page type appears more than once. */
|
|
7
|
+
export declare function findDuplicateUnsubPageTypes(html: string): typeof SINGLETON_BLOCK_RULES;
|
|
8
|
+
/** Pure core: count of unsubscribe blocks with no page type or page list chosen. */
|
|
9
|
+
export declare function countUnsubBlocksWithoutPage(html: string): number;
|
|
1
10
|
export declare const useUnsubscribeBlockValidator: () => {
|
|
2
11
|
validateUnsubscribeBlockUniqueness: (html: string) => boolean;
|
|
3
12
|
validateUnsubscribeBlockHasTemplate: (html: string) => boolean;
|
|
4
13
|
};
|
|
14
|
+
export {};
|
|
@@ -8,6 +8,5 @@ export declare const ACADEMY_LINKS: {
|
|
|
8
8
|
readonly EMAIL_EDITOR: "https://academy.insiderone.com/docs/email-drag-and-drop-editor";
|
|
9
9
|
readonly GLOBAL_UNSUBSCRIBE: "https://academy.insiderone.com/docs/global-unsubscribe-preference-center";
|
|
10
10
|
readonly AMP_FOR_EMAILS: "https://academy.insiderone.com/docs/amp-for-emails";
|
|
11
|
-
readonly EMAIL_RECOMMENDATION_BLOCK: "https://academy.insiderone.com/docs/new-editor-email-recommendation-block";
|
|
12
11
|
};
|
|
13
12
|
export type AcademyLinkKey = keyof typeof ACADEMY_LINKS;
|
|
@@ -3,9 +3,7 @@ import type { RecommendationFeedItem } from '@@/Types/recommendation';
|
|
|
3
3
|
export declare const URLS: {
|
|
4
4
|
RECOMMENDATION_API_URL: string;
|
|
5
5
|
PRODUCT_ATTRIBUTES_PATH: string;
|
|
6
|
-
RECOMMENDATION_STRATEGIES_PATH: string;
|
|
7
6
|
};
|
|
8
|
-
export declare const RRS_ACTIVE_EMAIL_FILTER = "[sr_strategies.status][=][active]*[sr_strategies.suitable_channels][~][EMAIL]";
|
|
9
7
|
export declare const QUERY_PARAMS: {
|
|
10
8
|
CLIENT_ID: string;
|
|
11
9
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stable discriminators for each save-validation rule site — one per rule that
|
|
3
|
+
* can produce a drawer row, kept in sync with the collector + legacy validator chains.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum SaveValidationRule {
|
|
6
|
+
CouponTagModified = "coupon-tag-modified",
|
|
7
|
+
DuplicateUnsubBlock = "duplicate-unsub-block",
|
|
8
|
+
UnsubBlockMissingTemplate = "unsub-block-missing-template",
|
|
9
|
+
LiquidSyntax = "liquid-syntax",
|
|
10
|
+
InvalidLinks = "invalid-links",
|
|
11
|
+
LinkCheckInProgress = "link-check-in-progress",
|
|
12
|
+
CustomFieldScript = "custom-field-script",
|
|
13
|
+
EmptyHtml = "empty-html",
|
|
14
|
+
MismatchedBraces = "mismatched-braces",
|
|
15
|
+
InvalidDynamicTag = "invalid-dynamic-tag",
|
|
16
|
+
InvalidCustomField = "invalid-custom-field",
|
|
17
|
+
ConditionsSyntax = "conditions-syntax",
|
|
18
|
+
WrongEqualityOperator = "wrong-equality-operator",
|
|
19
|
+
MissingIfEndif = "missing-if-endif",
|
|
20
|
+
ConditionTagSpacing = "condition-tag-spacing",
|
|
21
|
+
BracesInsideIfTag = "braces-inside-if-tag",
|
|
22
|
+
RecommendationRequiredFields = "recommendation-required-fields",
|
|
23
|
+
RecommendationFilters = "recommendation-filters",
|
|
24
|
+
InvalidImageType = "invalid-image-type",
|
|
25
|
+
CheckboxUnsubGroup = "checkbox-unsub-group",
|
|
26
|
+
RadioButtonUnsubGroup = "radio-button-unsub-group"
|
|
27
|
+
}
|
|
@@ -9,9 +9,8 @@ import { PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID } from './pricePlacem
|
|
|
9
9
|
import { ProductCountControl, PRODUCT_COUNT_CONTROL_ID } from './productCount';
|
|
10
10
|
import { ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID } from './productLayout';
|
|
11
11
|
import { ShuffleControl, SHUFFLE_CONTROL_ID } from './shuffle';
|
|
12
|
-
import { StrategyControl, STRATEGY_CONTROL_ID } from './strategy';
|
|
13
12
|
export declare const CONTROL_BLOCK_ID = "ui-elements-recommendation-block";
|
|
14
|
-
export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID,
|
|
13
|
+
export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, };
|
|
15
14
|
export * from './utils';
|
|
16
15
|
/**
|
|
17
16
|
* Main recommendation block control that composes all sub-controls
|
|
@@ -30,10 +29,7 @@ export declare class RecommendationBlockControl extends CommonControl {
|
|
|
30
29
|
private shuffleControl;
|
|
31
30
|
private pricePlacementControl;
|
|
32
31
|
private layoutOrientationControl;
|
|
33
|
-
private strategyControl;
|
|
34
32
|
getId(): string;
|
|
35
|
-
/** Every sub-control the coordinator owns, in panel order. */
|
|
36
|
-
private get _subControls();
|
|
37
33
|
getTemplate(): string;
|
|
38
34
|
onRender(): Promise<void>;
|
|
39
35
|
onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
|
|
@@ -111,15 +107,8 @@ export declare class RecommendationBlockControl extends CommonControl {
|
|
|
111
107
|
*/
|
|
112
108
|
private _listenStateUpdates;
|
|
113
109
|
/**
|
|
114
|
-
* Persists the current filter
|
|
115
|
-
*
|
|
116
|
-
* (strategyId must be in esd-ext-config before any save — SD-149105).
|
|
117
|
-
*
|
|
118
|
-
* `size` rides along because assigning a strategy overwrites it in the
|
|
119
|
-
* store only. Without this write, `_syncNodeConfigToStore` re-seeds the
|
|
120
|
-
* store from the stale node config on the next panel open, and a block
|
|
121
|
-
* whose saved HTML has the strategy's slot count gets rebuilt against the
|
|
122
|
-
* old one — resetting migrator-applied per-element styles.
|
|
110
|
+
* Persists the current filter state from Pinia store to the Stripo node config.
|
|
111
|
+
* This ensures filters survive template save/reload cycles.
|
|
123
112
|
*/
|
|
124
113
|
private _persistFiltersToNodeConfig;
|
|
125
114
|
}
|