@useinsider/guido 3.3.0-beta.b7e5793 → 3.3.0-beta.d5c796a
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/dist/components/Guido.vue.js +1 -1
- package/dist/components/Guido.vue2.js +42 -40
- package/dist/components/organisms/header/AiStatusPill.vue.js +18 -0
- package/dist/components/organisms/header/AiStatusPill.vue2.js +13 -0
- package/dist/components/organisms/header/MiddleSlot.vue.js +7 -7
- package/dist/components/organisms/header/MiddleSlot.vue2.js +8 -7
- package/dist/composables/useCortexBlueprintBridge.js +91 -0
- package/dist/composables/useEmailTemplateApplier.js +41 -0
- package/dist/composables/useGuidoStateBridge.js +48 -0
- package/dist/composables/useHtmlValidator.js +36 -41
- package/dist/composables/useRecommendation.js +2 -2
- package/dist/enums/extensions/recommendationBlock.js +41 -95
- package/dist/enums/unsubscribe.js +24 -25
- package/dist/extensions/Blocks/Checkbox/control.js +23 -23
- package/dist/extensions/Blocks/RadioButton/control.js +15 -15
- package/dist/extensions/Blocks/Recommendation/block.js +36 -43
- package/dist/extensions/Blocks/Recommendation/services/configService.js +26 -33
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +26 -35
- package/dist/guido.css +1 -1
- package/dist/src/components/organisms/header/AiStatusPill.vue.d.ts +2 -0
- package/dist/src/composables/useCortexBlueprintBridge.d.ts +28 -0
- package/dist/src/composables/useEmailTemplateApplier.d.ts +21 -0
- package/dist/src/composables/useGuidoStateBridge.d.ts +22 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +1 -5
- package/dist/src/enums/unsubscribe.d.ts +3 -8
- package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +3 -11
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +1 -7
- package/dist/src/stores/ai-status.d.ts +41 -0
- package/dist/src/stores/guido-email-editor.d.ts +41 -0
- package/dist/stores/ai-status.js +25 -0
- package/dist/stores/guido-email-editor.js +20 -0
- package/package.json +1 -1
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +0 -33
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +0 -21
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ModificationDescription as
|
|
2
|
-
import { CURRENT_CONFIG_VERSION as l, DEFAULT_NODE_CONFIG as
|
|
1
|
+
import { ModificationDescription as h } from "../../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
|
|
2
|
+
import { CURRENT_CONFIG_VERSION as l, DEFAULT_NODE_CONFIG as r } from "../constants/defaultConfig.js";
|
|
3
3
|
import { setCurrencyAttributes as D } from "../controls/main/utils.js";
|
|
4
4
|
import { hasMinimalConfig as A } from "../types/nodeConfig.js";
|
|
5
5
|
function S(e) {
|
|
@@ -8,7 +8,7 @@ function S(e) {
|
|
|
8
8
|
function N(e) {
|
|
9
9
|
return e === "." || e === "," || e === " " || e === "";
|
|
10
10
|
}
|
|
11
|
-
class
|
|
11
|
+
class V {
|
|
12
12
|
// ========================================================================
|
|
13
13
|
// Read Operations
|
|
14
14
|
// ========================================================================
|
|
@@ -83,7 +83,7 @@ class M {
|
|
|
83
83
|
* @returns The new complete configuration
|
|
84
84
|
*/
|
|
85
85
|
static updateConfig(i, t, o, n) {
|
|
86
|
-
const
|
|
86
|
+
const c = this.getConfig(t), u = this.deepMerge(c, o);
|
|
87
87
|
return this.saveConfig(i, t, u, n), u;
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
@@ -91,28 +91,21 @@ class M {
|
|
|
91
91
|
*
|
|
92
92
|
* Called when a block is first created (dropped into template).
|
|
93
93
|
* Can optionally merge in partial config from migration.
|
|
94
|
-
*
|
|
95
|
-
* The `wasFreshDrop` flag distinguishes a brand-new drop (no prior config)
|
|
96
|
-
* from a clone (Stripo replays the source's setNodeConfig payload before
|
|
97
|
-
* onCreated fires). Callers use this to skip side-effects already inherited
|
|
98
|
-
* from the source.
|
|
99
94
|
* @example
|
|
100
95
|
* // In Block.onCreated lifecycle
|
|
101
|
-
*
|
|
96
|
+
* RecommendationConfigService.initializeConfig(this.api, node);
|
|
102
97
|
* @param api - Stripo extension API with document modifier
|
|
103
98
|
* @param node - The immutable HTML node to initialize
|
|
104
99
|
* @param partialConfig - Optional partial config to merge with defaults
|
|
105
|
-
* @returns The initialized configuration
|
|
100
|
+
* @returns The initialized configuration
|
|
106
101
|
*/
|
|
107
102
|
static initializeConfig(i, t, o) {
|
|
108
|
-
if (this.hasConfig(t))
|
|
109
|
-
return { config: o ? this.updateConfig(i, t, o, "Initialize recommendation block") : this.getConfig(t), wasFreshDrop: !1 };
|
|
110
103
|
const n = o ? this.mergeWithDefaults(o) : this.cloneDefaults();
|
|
111
104
|
return this.saveConfig(i, t, n, "Initialize recommendation block"), D({
|
|
112
105
|
currentNode: t,
|
|
113
106
|
documentModifier: i.getDocumentModifier(),
|
|
114
107
|
currency: n.currency
|
|
115
|
-
}),
|
|
108
|
+
}), n;
|
|
116
109
|
}
|
|
117
110
|
/**
|
|
118
111
|
* Save complete configuration to a node
|
|
@@ -125,9 +118,9 @@ class M {
|
|
|
125
118
|
*/
|
|
126
119
|
static saveConfig(i, t, o, n) {
|
|
127
120
|
try {
|
|
128
|
-
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new
|
|
129
|
-
} catch (
|
|
130
|
-
console.warn("[RecommendationConfigService] Failed to save config:",
|
|
121
|
+
i.getDocumentModifier().modifyHtml(t).setNodeConfig(o).apply(new h(n));
|
|
122
|
+
} catch (c) {
|
|
123
|
+
console.warn("[RecommendationConfigService] Failed to save config:", c);
|
|
131
124
|
}
|
|
132
125
|
}
|
|
133
126
|
// ========================================================================
|
|
@@ -164,29 +157,29 @@ class M {
|
|
|
164
157
|
s && typeof s == "object" && (Object.assign(o, s), o.configVersion = l);
|
|
165
158
|
} catch {
|
|
166
159
|
}
|
|
167
|
-
const
|
|
168
|
-
|
|
160
|
+
const c = t.getAttribute("data-layout");
|
|
161
|
+
c === "list" || c === "horizontal" ? o.layout = "list" : (c === "grid" || c === "vertical") && (o.layout = "grid");
|
|
169
162
|
const u = t.getAttribute("data-card-composition");
|
|
170
163
|
u && (o.composition = u.split(",").filter(Boolean));
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
164
|
+
const p = t.getAttribute("data-column-spacing");
|
|
165
|
+
p && (o.columnSpacing = parseInt(p) || r.columnSpacing);
|
|
166
|
+
const b = t.getAttribute("data-row-spacing");
|
|
167
|
+
if (b && (o.rowSpacing = parseInt(b) || r.rowSpacing), !o.currency) {
|
|
175
168
|
const s = t.getAttribute("currency"), y = t.getAttribute("currency-symbol"), d = t.getAttribute("currency-alignment"), f = t.getAttribute("currency-thousand-separator"), g = t.getAttribute("currency-decimal-separator"), m = t.getAttribute("currency-decimal-count");
|
|
176
169
|
if (s || y || d || f || g || m) {
|
|
177
|
-
const a =
|
|
170
|
+
const a = r.currency, C = m ? parseInt(m) : NaN;
|
|
178
171
|
o.currency = {
|
|
179
172
|
code: s ?? a.code,
|
|
180
173
|
symbol: y ?? a.symbol,
|
|
181
174
|
alignment: d === "0" ? "before" : "after",
|
|
182
|
-
decimalCount: Number.isFinite(
|
|
175
|
+
decimalCount: Number.isFinite(C) ? C : a.decimalCount,
|
|
183
176
|
decimalSeparator: S(g) ? g : a.decimalSeparator,
|
|
184
177
|
thousandSeparator: N(f) ? f : a.thousandSeparator
|
|
185
178
|
};
|
|
186
179
|
}
|
|
187
180
|
}
|
|
188
181
|
}
|
|
189
|
-
return this.initializeConfig(i, t, o)
|
|
182
|
+
return this.initializeConfig(i, t, o);
|
|
190
183
|
}
|
|
191
184
|
/**
|
|
192
185
|
* Check if configuration needs migration
|
|
@@ -204,12 +197,12 @@ class M {
|
|
|
204
197
|
*/
|
|
205
198
|
static cloneDefaults() {
|
|
206
199
|
return {
|
|
207
|
-
...
|
|
208
|
-
currency: { ...
|
|
209
|
-
omnibusPrice: { ...
|
|
210
|
-
omnibusDiscount: { ...
|
|
211
|
-
composition: [...
|
|
212
|
-
visibility: { ...
|
|
200
|
+
...r,
|
|
201
|
+
currency: { ...r.currency },
|
|
202
|
+
omnibusPrice: { ...r.omnibusPrice },
|
|
203
|
+
omnibusDiscount: { ...r.omnibusDiscount },
|
|
204
|
+
composition: [...r.composition],
|
|
205
|
+
visibility: { ...r.visibility },
|
|
213
206
|
filters: [],
|
|
214
207
|
productIds: [],
|
|
215
208
|
recommendationId: 0
|
|
@@ -279,5 +272,5 @@ class M {
|
|
|
279
272
|
}
|
|
280
273
|
}
|
|
281
274
|
export {
|
|
282
|
-
|
|
275
|
+
V as RecommendationConfigService
|
|
283
276
|
};
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RecommendationFeedSourceMaps as S, getOperatorOptions as R, PriceAttributes as y } from "../../../../enums/extensions/recommendationBlock.js";
|
|
2
2
|
import { useRecommendationApi as C } from "../../../../services/recommendationApi.js";
|
|
3
3
|
import { useConfigStore as G } from "../../../../stores/config.js";
|
|
4
4
|
import { defineStore as P } from "pinia";
|
|
5
5
|
import { DEFAULT_CARDS_IN_ROW as F } from "../constants/layout.js";
|
|
6
6
|
import { EXCLUDED_ALGORITHM_IDS as D } from "../constants/defaultConfig.js";
|
|
7
|
-
import { getDefaultProducts as
|
|
7
|
+
import { getDefaultProducts as g } from "../templates/utils.js";
|
|
8
8
|
import { generateCompleteFilterQuery as b } from "../utils/filterUtil.js";
|
|
9
9
|
import { isFilterValid as w } from "../validation/filterSchema.js";
|
|
10
|
-
import { isConfigValid as v } from "../validation/requiredFields.js";
|
|
11
10
|
const h = C();
|
|
12
|
-
let
|
|
11
|
+
let u = null, m = null, d = null;
|
|
13
12
|
function k() {
|
|
14
13
|
return {
|
|
15
14
|
cardsInRow: F,
|
|
@@ -49,7 +48,7 @@ function I() {
|
|
|
49
48
|
filterSnapshot: null
|
|
50
49
|
};
|
|
51
50
|
}
|
|
52
|
-
const
|
|
51
|
+
const v = () => ({
|
|
53
52
|
recommendationCampaignUrls: {},
|
|
54
53
|
activePredictiveAlgorithms: [],
|
|
55
54
|
languages: {},
|
|
@@ -58,8 +57,8 @@ const N = () => ({
|
|
|
58
57
|
blockStates: {},
|
|
59
58
|
currentRecommendationId: null,
|
|
60
59
|
configVersion: 0
|
|
61
|
-
}),
|
|
62
|
-
state: () =>
|
|
60
|
+
}), _ = P("guidoRecommendationExtension", {
|
|
61
|
+
state: () => v(),
|
|
63
62
|
getters: {
|
|
64
63
|
// ====================================================================
|
|
65
64
|
// Proxy Getters — Backward Compatible Access to Current Block State
|
|
@@ -114,12 +113,12 @@ const N = () => ({
|
|
|
114
113
|
return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
|
|
115
114
|
},
|
|
116
115
|
getActivePredictiveAlgorithms: (t) => {
|
|
117
|
-
const e =
|
|
118
|
-
return t.activePredictiveAlgorithms.filter((
|
|
119
|
-
|
|
120
|
-
}),
|
|
121
|
-
text:
|
|
122
|
-
value:
|
|
116
|
+
const e = [];
|
|
117
|
+
return t.activePredictiveAlgorithms.filter((r) => !D.includes(r)).forEach((r) => {
|
|
118
|
+
e.push(...S.filter((n) => n.id === r));
|
|
119
|
+
}), e.map((r) => ({
|
|
120
|
+
text: r.name,
|
|
121
|
+
value: r.key
|
|
123
122
|
}));
|
|
124
123
|
},
|
|
125
124
|
getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
|
|
@@ -294,11 +293,11 @@ const N = () => ({
|
|
|
294
293
|
// ====================================================================
|
|
295
294
|
async fetchRecommendationCreateData() {
|
|
296
295
|
if (!this.activePredictiveAlgorithms.length) {
|
|
297
|
-
if (
|
|
298
|
-
await
|
|
296
|
+
if (u) {
|
|
297
|
+
await u;
|
|
299
298
|
return;
|
|
300
299
|
}
|
|
301
|
-
|
|
300
|
+
u = (async () => {
|
|
302
301
|
const {
|
|
303
302
|
activePredictiveAlgorithms: t,
|
|
304
303
|
languages: e,
|
|
@@ -311,26 +310,26 @@ const N = () => ({
|
|
|
311
310
|
this.currencyList = r;
|
|
312
311
|
})();
|
|
313
312
|
try {
|
|
314
|
-
await
|
|
313
|
+
await u;
|
|
315
314
|
} finally {
|
|
316
|
-
|
|
315
|
+
u = null;
|
|
317
316
|
}
|
|
318
317
|
}
|
|
319
318
|
},
|
|
320
319
|
async fetchRecommendationFilters() {
|
|
321
320
|
if (!Object.keys(this.filterList).length) {
|
|
322
|
-
if (
|
|
323
|
-
await
|
|
321
|
+
if (m) {
|
|
322
|
+
await m;
|
|
324
323
|
return;
|
|
325
324
|
}
|
|
326
|
-
|
|
325
|
+
m = (async () => {
|
|
327
326
|
const t = await h.fetchRecommendationFilters();
|
|
328
327
|
this.filterList = t;
|
|
329
328
|
})();
|
|
330
329
|
try {
|
|
331
|
-
await
|
|
330
|
+
await m;
|
|
332
331
|
} finally {
|
|
333
|
-
|
|
332
|
+
m = null;
|
|
334
333
|
}
|
|
335
334
|
}
|
|
336
335
|
},
|
|
@@ -399,14 +398,6 @@ const N = () => ({
|
|
|
399
398
|
generateFilterQuery() {
|
|
400
399
|
return b(this.recommendationConfigs.filters);
|
|
401
400
|
},
|
|
402
|
-
/**
|
|
403
|
-
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
404
|
-
* (not a getter) so reading it does not register reactive tracking on
|
|
405
|
-
* every block's recommendationConfigs across user edits.
|
|
406
|
-
*/
|
|
407
|
-
hasInvalidBlock() {
|
|
408
|
-
return Object.values(this.blockStates).some((t) => !v(t.recommendationConfigs, this));
|
|
409
|
-
},
|
|
410
401
|
// ====================================================================
|
|
411
402
|
// Per-Block Product Fetching
|
|
412
403
|
// ====================================================================
|
|
@@ -426,7 +417,7 @@ const N = () => ({
|
|
|
426
417
|
},
|
|
427
418
|
async _doFetchProducts() {
|
|
428
419
|
var p;
|
|
429
|
-
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p =
|
|
420
|
+
const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p = S.find((l) => l.key === r.strategy)) == null ? void 0 : p.path) || "", o = G(), s = parseInt(r.size) || 6, a = {
|
|
430
421
|
locale: r.language,
|
|
431
422
|
currency: r.currencySettings.value,
|
|
432
423
|
partnerName: o.partnerName,
|
|
@@ -442,15 +433,15 @@ const N = () => ({
|
|
|
442
433
|
f = [];
|
|
443
434
|
}
|
|
444
435
|
if (this.blockStates[t]) {
|
|
445
|
-
const l = f.length > 0 ? f :
|
|
436
|
+
const l = f.length > 0 ? f : g(s);
|
|
446
437
|
l.length < s ? this.blockStates[t].recommendationProducts = [
|
|
447
438
|
...l,
|
|
448
|
-
...
|
|
439
|
+
...g(s - l.length)
|
|
449
440
|
] : l.length > s ? this.blockStates[t].recommendationProducts = l.slice(0, s) : this.blockStates[t].recommendationProducts = l;
|
|
450
441
|
}
|
|
451
442
|
}
|
|
452
443
|
}
|
|
453
444
|
});
|
|
454
445
|
export {
|
|
455
|
-
|
|
446
|
+
_ as useRecommendationExtensionStore
|
|
456
447
|
};
|
package/dist/guido.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.gap-16[data-v-3b53a736],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-4e2a4adb]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-
|
|
1
|
+
.gap-16[data-v-3b53a736],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-cd76c125] .in-button-v2__wrapper{line-height:0}[data-v-22226124] .in-segments-wrapper__button_selected,[data-v-22226124] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb;color:#0010ac;border-color:#0010ac}[data-v-2cb418af] .in-progress-wrapper__progress p span:last-child{display:none!important}[data-v-2cb418af] .in-progress-description-status{display:none!important}.ai-status-pill[data-v-dea97ab5]{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;margin:0 8px;border-radius:12px;background:#3c5af014;color:#2c5282;font-size:12px;font-weight:500;line-height:1.2;-webkit-user-select:none;user-select:none}.ai-status-pill__dot[data-v-dea97ab5]{width:6px;height:6px;border-radius:50%;background:#3c5af0;animation:ai-pulse-dea97ab5 1.4s ease-in-out infinite}.ai-status-pill__label[data-v-dea97ab5]{white-space:nowrap}@keyframes ai-pulse-dea97ab5{0%,to{opacity:.4;transform:scale(1)}50%{opacity:1;transform:scale(1.15)}}.view-options-wrapper[data-v-195ab6d4]{position:relative;display:inline-block}.new-tag[data-v-195ab6d4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-195ab6d4] .guido__view-option-selection-desktop svg,[data-v-195ab6d4] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-195ab6d4] .in-segments-wrapper__button_selected,[data-v-195ab6d4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-195ab6d4] .in-tooltip-wrapper__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-64c52560]{gap:8px}.version-history__toolbar[data-v-64c52560]{gap:4px}.view-options-wrapper[data-v-d405ca59]{position:relative;display:inline-block}.new-tag[data-v-d405ca59]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-d405ca59] .guido__verion-history-view-option-selection-desktop svg,[data-v-d405ca59] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-d405ca59] .in-segments-wrapper__button_selected,[data-v-d405ca59] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-d405ca59] .in-tooltip-wrapper__icon{cursor:pointer}.auto-save-toggle[data-v-2c964af4]{position:relative}.auto-save-toggle__info-box[data-v-2c964af4]{position:absolute;top:100%;left:0;z-index:10;width:280px}.editor-actions[data-v-4e2a4adb]{gap:4px}.header-wrapper[data-v-5c02dcc7]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-cdee3452]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-cdee3452]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-cdee3452]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-df672485]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-df672485]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-df672485]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-df672485]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-df672485]{object-fit:cover;transform:scale(1)}[data-v-43c617a7] .guido__verion-history-view-option-selection-desktop svg,[data-v-43c617a7] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-43c617a7] .in-segments-wrapper__button_selected,[data-v-43c617a7] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}.error-list[data-v-c3fd5d4b]{gap:16px}.desktop-browser-header[data-v-d86c5af5]{height:79px;min-height:79px}.desktop-browser-header__left[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:378px}.desktop-browser-header__center[data-v-d86c5af5]{height:79px;background-repeat:repeat-x;background-size:auto 100%;background-position:left top}.desktop-browser-header__right[data-v-d86c5af5]{-webkit-user-drag:none;height:79px;width:112px}.desktop-preview[data-v-988f8da6]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-988f8da6]{min-height:504px}.iframe-wrapper[data-v-e0424e99]{width:258px}.iframe-scaled[data-v-e0424e99]{width:320px;height:124.0310077519%;transform:scale(.80625);transform-origin:top left}.cropped-text[data-v-eb3d05d7]{width:220px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.mobile-preview-wrapper__phone[data-v-3f472f96]{width:282px}.mobile-preview-wrapper__phone img[data-v-3f472f96]{object-fit:cover;border-radius:44px}.mobile-preview-wrapper__content[data-v-3f472f96]{width:258px;height:450px;left:12px}[data-v-7419ae06] .vueperslides__bullets,[data-v-796d193b] .vueperslides__bullets{pointer-events:none!important}[data-v-796d193b] .vueperslides__parallax-wrapper{height:110px!important}[data-v-cadfc82d] .vueperslides__bullets{pointer-events:none!important}[data-v-cadfc82d] .vueperslides__parallax-wrapper{height:110px!important}
|
|
@@ -0,0 +1,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<{}>>, {}>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridges cortex-fe's chat store to Guido's Stripo editor.
|
|
3
|
+
*
|
|
4
|
+
* cortex-fe is a Module Federation MFE that registers `defineStore('chat', …)`
|
|
5
|
+
* on the host's shared (singleton) Pinia. Guido — bundled inside MFE consumers
|
|
6
|
+
* that also share that pinia — reads the same store at runtime via
|
|
7
|
+
* `getActivePinia()._s.get('chat')`. No build-time dep on cortex-fe.
|
|
8
|
+
*
|
|
9
|
+
* The bridge handles three segment shapes:
|
|
10
|
+
*
|
|
11
|
+
* - `blueprint` segments with `blueprintType === 'email_template'` are
|
|
12
|
+
* applied to the Stripo editor (immediate on first sighting, debounced on
|
|
13
|
+
* update, identical-html no-ops).
|
|
14
|
+
* - `tool` segments toggle the AI status pill via `useAiStatusStore`. The
|
|
15
|
+
* pill goes up when `isRunning: true` and clears on `isRunning: false`,
|
|
16
|
+
* `error: true`, or any `error` segment / message-level `isError` flag.
|
|
17
|
+
* - `error` segments (and message-level `isError` / `isCancelled`) trigger
|
|
18
|
+
* a localized toaster and clear the status pill.
|
|
19
|
+
*
|
|
20
|
+
* In dev (`import.meta.env.DEV`) every observed segment + message-level flag
|
|
21
|
+
* change is also `console.debug`-logged with the prefix `[guido:cortex]` so a
|
|
22
|
+
* developer can watch the agent stream in real time. In production this is
|
|
23
|
+
* gated behind `localStorage.guido:debug:ai === '1'`.
|
|
24
|
+
*
|
|
25
|
+
* If cortex-fe isn't loaded the chat store is undefined and the bridge is a
|
|
26
|
+
* no-op (intentional — Guido must still work standalone).
|
|
27
|
+
*/
|
|
28
|
+
export declare const useCortexBlueprintBridge: () => void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type ApplyStatus = 'pending' | 'applying' | 'applied' | 'failed';
|
|
2
|
+
/**
|
|
3
|
+
* Applies email_template blueprints from the chat agent to the Stripo editor.
|
|
4
|
+
*
|
|
5
|
+
* - blueprint_create + manual Apply click: immediate.
|
|
6
|
+
* - blueprint_update: debounced 250 ms trailing so rapid mid-stream updates
|
|
7
|
+
* don't thrash updateHtmlAndCss.
|
|
8
|
+
*/
|
|
9
|
+
export declare const useEmailTemplateApplier: () => {
|
|
10
|
+
applyStatus: import("vue").Ref<Record<string, ApplyStatus>>;
|
|
11
|
+
applyTemplate: (blueprintId: string, data: {
|
|
12
|
+
html?: string;
|
|
13
|
+
css?: string;
|
|
14
|
+
}) => void;
|
|
15
|
+
applyTemplateDebounced: (blueprintId: string, data: {
|
|
16
|
+
html?: string;
|
|
17
|
+
css?: string;
|
|
18
|
+
}) => void;
|
|
19
|
+
};
|
|
20
|
+
export declare const resetEmailTemplateApplier: () => void;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound bridge — publishes the current editor's html/css to the shared
|
|
3
|
+
* Pinia store `guidoEmailEditor` so cortex-fe can read it at chat-stream
|
|
4
|
+
* submit time and forward it as `clientState.editor`. This is what enables
|
|
5
|
+
* sub-case 1.3 (refine an already-loaded template via the email-agent).
|
|
6
|
+
*
|
|
7
|
+
* The bridge writes on three triggers:
|
|
8
|
+
*
|
|
9
|
+
* 1. Stripo finishes initializing — first snapshot.
|
|
10
|
+
* 2. Editor `hasChanges` flips to true — debounced 500 ms so a streaming
|
|
11
|
+
* Stripo edit doesn't thrash the store.
|
|
12
|
+
* 3. Editor `hasChanges` flips back to false (post-save / autosave) —
|
|
13
|
+
* immediate, since this is the canonical "saved" snapshot.
|
|
14
|
+
*
|
|
15
|
+
* `getTemplateData()` is a Stripo iframe call; it must not run before
|
|
16
|
+
* `isStripoInitialized` is true. The bridge guards against that.
|
|
17
|
+
*
|
|
18
|
+
* If cortex-fe isn't loaded the store still gets written — that's fine;
|
|
19
|
+
* the store has zero overhead and any future reader will find consistent
|
|
20
|
+
* state. The bridge is a one-way pipe with no consumer dependency.
|
|
21
|
+
*/
|
|
22
|
+
export declare const useGuidoStateBridge: () => void;
|
|
@@ -6,11 +6,7 @@ export declare const URLS: {
|
|
|
6
6
|
export declare const QUERY_PARAMS: {
|
|
7
7
|
CLIENT_ID: string;
|
|
8
8
|
};
|
|
9
|
-
|
|
10
|
-
* Get recommendation feed source maps lazily so translated names resolve at access time.
|
|
11
|
-
* Must be called within a Vue component context or after Pinia is initialized.
|
|
12
|
-
*/
|
|
13
|
-
export declare const getRecommendationFeedSourceMaps: () => RecommendationFeedItem[];
|
|
9
|
+
export declare const RecommendationFeedSourceMaps: RecommendationFeedItem[];
|
|
14
10
|
export declare const PriceAttributes: string[];
|
|
15
11
|
export declare const currencyLocationMaps: TextValueObject[];
|
|
16
12
|
export declare const currencyOperators: TextValueObject[];
|
|
@@ -18,14 +18,9 @@ export declare const PRODUCT_TYPE_URL_SEGMENTS: {
|
|
|
18
18
|
readonly 97: "email";
|
|
19
19
|
};
|
|
20
20
|
export declare const INSIDER_ID = "iid";
|
|
21
|
-
export declare const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* Must be called within a Vue component context or after Pinia is initialized.
|
|
25
|
-
*/
|
|
26
|
-
export declare const getDefaultUnsubscribeGroup: () => {
|
|
27
|
-
name: string;
|
|
28
|
-
sendGridId: string;
|
|
21
|
+
export declare const DEFAULT_UNSUBSCRIBE_GROUP: {
|
|
22
|
+
readonly name: "Global Unsubscribe";
|
|
23
|
+
readonly sendGridId: "G";
|
|
29
24
|
};
|
|
30
25
|
export declare const UNSUBSCRIBE_PAGES_LINK = "/email/unsubscribe-pages";
|
|
31
26
|
export declare const PAGE_TYPES: {
|
|
@@ -95,23 +95,15 @@ export declare class RecommendationConfigService {
|
|
|
95
95
|
*
|
|
96
96
|
* Called when a block is first created (dropped into template).
|
|
97
97
|
* Can optionally merge in partial config from migration.
|
|
98
|
-
*
|
|
99
|
-
* The `wasFreshDrop` flag distinguishes a brand-new drop (no prior config)
|
|
100
|
-
* from a clone (Stripo replays the source's setNodeConfig payload before
|
|
101
|
-
* onCreated fires). Callers use this to skip side-effects already inherited
|
|
102
|
-
* from the source.
|
|
103
98
|
* @example
|
|
104
99
|
* // In Block.onCreated lifecycle
|
|
105
|
-
*
|
|
100
|
+
* RecommendationConfigService.initializeConfig(this.api, node);
|
|
106
101
|
* @param api - Stripo extension API with document modifier
|
|
107
102
|
* @param node - The immutable HTML node to initialize
|
|
108
103
|
* @param partialConfig - Optional partial config to merge with defaults
|
|
109
|
-
* @returns The initialized configuration
|
|
104
|
+
* @returns The initialized configuration
|
|
110
105
|
*/
|
|
111
|
-
static initializeConfig(api: DocumentModifierApi, node: ImmutableHtmlNode, partialConfig?: PartialNodeConfig):
|
|
112
|
-
config: RecommendationNodeConfig;
|
|
113
|
-
wasFreshDrop: boolean;
|
|
114
|
-
};
|
|
106
|
+
static initializeConfig(api: DocumentModifierApi, node: ImmutableHtmlNode, partialConfig?: PartialNodeConfig): RecommendationNodeConfig;
|
|
115
107
|
/**
|
|
116
108
|
* Save complete configuration to a node
|
|
117
109
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationProduct } from '@@/Types/recommendation';
|
|
2
|
-
|
|
2
|
+
interface PerBlockConfigs {
|
|
3
3
|
cardsInRow: number;
|
|
4
4
|
currencySettings: {
|
|
5
5
|
name: string;
|
|
@@ -272,12 +272,6 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
|
|
|
272
272
|
deleteFilter(filter: Filter): void;
|
|
273
273
|
addFilter(filter: Filter): void;
|
|
274
274
|
generateFilterQuery(): string;
|
|
275
|
-
/**
|
|
276
|
-
* Validation-only check invoked at save-CTA time. Defined as an action
|
|
277
|
-
* (not a getter) so reading it does not register reactive tracking on
|
|
278
|
-
* every block's recommendationConfigs across user edits.
|
|
279
|
-
*/
|
|
280
|
-
hasInvalidBlock(): boolean;
|
|
281
275
|
fetchRecommendationProducts(): Promise<void>;
|
|
282
276
|
_doFetchProducts(): Promise<void>;
|
|
283
277
|
}>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight read-only store the cortex-fe blueprint bridge writes into and
|
|
3
|
+
* the editor toolbar reads from to show the "AI is generating…" pill while a
|
|
4
|
+
* tool call is in flight. State + getters only — per architecture invariant
|
|
5
|
+
* the bridge mutates state directly via `$patch`, no actions live here.
|
|
6
|
+
*/
|
|
7
|
+
export declare const useAiStatusStore: import("pinia").StoreDefinition<"guidoAiStatus", {
|
|
8
|
+
/** A tool is currently running on the agent side. */
|
|
9
|
+
isWorking: boolean;
|
|
10
|
+
/** Tool name the agent is currently invoking, e.g. `tool__qmechanics__compile_template`. */
|
|
11
|
+
currentTool: string;
|
|
12
|
+
/** Last user-facing error message from the stream, cleared on the next tool_call. */
|
|
13
|
+
lastError: string;
|
|
14
|
+
}, {
|
|
15
|
+
/** Show the toolbar pill iff a tool is running AND no error overrides it. */
|
|
16
|
+
showStatusPill: (state: {
|
|
17
|
+
isWorking: boolean;
|
|
18
|
+
currentTool: string;
|
|
19
|
+
lastError: string;
|
|
20
|
+
} & import("pinia").PiniaCustomStateProperties<{
|
|
21
|
+
/** A tool is currently running on the agent side. */
|
|
22
|
+
isWorking: boolean;
|
|
23
|
+
/** Tool name the agent is currently invoking, e.g. `tool__qmechanics__compile_template`. */
|
|
24
|
+
currentTool: string;
|
|
25
|
+
/** Last user-facing error message from the stream, cleared on the next tool_call. */
|
|
26
|
+
lastError: string;
|
|
27
|
+
}>) => boolean;
|
|
28
|
+
/** Display label for the pill — short, suitable for inline UI. */
|
|
29
|
+
statusLabel: (state: {
|
|
30
|
+
isWorking: boolean;
|
|
31
|
+
currentTool: string;
|
|
32
|
+
lastError: string;
|
|
33
|
+
} & import("pinia").PiniaCustomStateProperties<{
|
|
34
|
+
/** A tool is currently running on the agent side. */
|
|
35
|
+
isWorking: boolean;
|
|
36
|
+
/** Tool name the agent is currently invoking, e.g. `tool__qmechanics__compile_template`. */
|
|
37
|
+
currentTool: string;
|
|
38
|
+
/** Last user-facing error message from the stream, cleared on the next tool_call. */
|
|
39
|
+
lastError: string;
|
|
40
|
+
}>) => string;
|
|
41
|
+
}, {}>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound contract Guido publishes to the host's shared Pinia singleton so
|
|
3
|
+
* cortex-fe can pick up the current editor state and forward it as
|
|
4
|
+
* `clientState.editor` on the next chat-stream POST.
|
|
5
|
+
*
|
|
6
|
+
* State + getters only — `useGuidoStateBridge` writes via `$patch`, no actions
|
|
7
|
+
* live here (architecture invariant).
|
|
8
|
+
*
|
|
9
|
+
* Store id `guidoEmailEditor` is cross-MFE: cortex-fe reads it via
|
|
10
|
+
* `pinia._s.get('guidoEmailEditor')` at runtime. The internal Guido editor
|
|
11
|
+
* store keeps id `guidoEditor` — these are intentionally separate. The
|
|
12
|
+
* internal store carries UI state that cortex-fe should not see; this public
|
|
13
|
+
* store carries the contract Guido is willing to share.
|
|
14
|
+
*/
|
|
15
|
+
export declare const useGuidoEmailEditorStore: import("pinia").StoreDefinition<"guidoEmailEditor", {
|
|
16
|
+
/** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
|
|
17
|
+
html: string;
|
|
18
|
+
/** Current Stripo CSS — es-p* utility classes used by the html. */
|
|
19
|
+
css: string;
|
|
20
|
+
/** Wall-clock ms when html/css were last written by the bridge. */
|
|
21
|
+
lastUpdatedAt: number;
|
|
22
|
+
/** Template id from the editor config, for cortex-fe to scope per-template. */
|
|
23
|
+
templateId: string;
|
|
24
|
+
}, {
|
|
25
|
+
/** True once the bridge has published at least one snapshot. */
|
|
26
|
+
hasSnapshot: (state: {
|
|
27
|
+
html: string;
|
|
28
|
+
css: string;
|
|
29
|
+
lastUpdatedAt: number;
|
|
30
|
+
templateId: string;
|
|
31
|
+
} & import("pinia").PiniaCustomStateProperties<{
|
|
32
|
+
/** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
|
|
33
|
+
html: string;
|
|
34
|
+
/** Current Stripo CSS — es-p* utility classes used by the html. */
|
|
35
|
+
css: string;
|
|
36
|
+
/** Wall-clock ms when html/css were last written by the bridge. */
|
|
37
|
+
lastUpdatedAt: number;
|
|
38
|
+
/** Template id from the editor config, for cortex-fe to scope per-template. */
|
|
39
|
+
templateId: string;
|
|
40
|
+
}>) => boolean;
|
|
41
|
+
}, {}>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineStore as o } from "pinia";
|
|
2
|
+
const i = o("guidoAiStatus", {
|
|
3
|
+
state: () => ({
|
|
4
|
+
/** A tool is currently running on the agent side. */
|
|
5
|
+
isWorking: !1,
|
|
6
|
+
/** Tool name the agent is currently invoking, e.g. `tool__qmechanics__compile_template`. */
|
|
7
|
+
currentTool: "",
|
|
8
|
+
/** Last user-facing error message from the stream, cleared on the next tool_call. */
|
|
9
|
+
lastError: ""
|
|
10
|
+
}),
|
|
11
|
+
getters: {
|
|
12
|
+
/** Show the toolbar pill iff a tool is running AND no error overrides it. */
|
|
13
|
+
showStatusPill: (r) => r.isWorking && r.lastError === "",
|
|
14
|
+
/** Display label for the pill — short, suitable for inline UI. */
|
|
15
|
+
statusLabel: (r) => {
|
|
16
|
+
if (!r.isWorking)
|
|
17
|
+
return "";
|
|
18
|
+
const t = r.currentTool.replace(/^tool__[^_]+__/, "");
|
|
19
|
+
return t ? `AI: ${t}…` : "AI is generating…";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
export {
|
|
24
|
+
i as useAiStatusStore
|
|
25
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineStore as e } from "pinia";
|
|
2
|
+
const d = e("guidoEmailEditor", {
|
|
3
|
+
state: () => ({
|
|
4
|
+
/** Current Stripo HTML — stripe tables only, no DOCTYPE/wrapper. */
|
|
5
|
+
html: "",
|
|
6
|
+
/** Current Stripo CSS — es-p* utility classes used by the html. */
|
|
7
|
+
css: "",
|
|
8
|
+
/** Wall-clock ms when html/css were last written by the bridge. */
|
|
9
|
+
lastUpdatedAt: 0,
|
|
10
|
+
/** Template id from the editor config, for cortex-fe to scope per-template. */
|
|
11
|
+
templateId: ""
|
|
12
|
+
}),
|
|
13
|
+
getters: {
|
|
14
|
+
/** True once the bridge has published at least one snapshot. */
|
|
15
|
+
hasSnapshot: (t) => t.lastUpdatedAt > 0 && t.html !== ""
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
export {
|
|
19
|
+
d as useGuidoEmailEditorStore
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@useinsider/guido",
|
|
3
|
-
"version": "3.3.0-beta.
|
|
3
|
+
"version": "3.3.0-beta.d5c796a",
|
|
4
4
|
"description": "Guido is a Vue + TypeScript wrapper for Email Plugin. Easily embed the email editor in your Vue applications.",
|
|
5
5
|
"main": "./dist/guido.umd.cjs",
|
|
6
6
|
"module": "./dist/library.js",
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
const o = [
|
|
2
|
-
{
|
|
3
|
-
key: "locale",
|
|
4
|
-
getValue: (e) => e.language,
|
|
5
|
-
getAvailableOptions: (e) => Object.keys(e.languages)
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
key: "currency",
|
|
9
|
-
getValue: (e) => e.currencySettings.value,
|
|
10
|
-
getAvailableOptions: (e) => e.currencyList.map((n) => n.text)
|
|
11
|
-
}
|
|
12
|
-
], l = "newsletter.recommendation-fill-required-fields";
|
|
13
|
-
function u(e, n) {
|
|
14
|
-
return o.filter((t) => {
|
|
15
|
-
var a;
|
|
16
|
-
if (t.condition && !t.condition(e))
|
|
17
|
-
return !1;
|
|
18
|
-
const i = t.getValue(e);
|
|
19
|
-
if (!i)
|
|
20
|
-
return !0;
|
|
21
|
-
const r = (a = t.getAvailableOptions) == null ? void 0 : a.call(t, n);
|
|
22
|
-
return r !== void 0 && !r.includes(i);
|
|
23
|
-
}).map((t) => t.key);
|
|
24
|
-
}
|
|
25
|
-
function s(e, n) {
|
|
26
|
-
return u(e, n).length === 0;
|
|
27
|
-
}
|
|
28
|
-
export {
|
|
29
|
-
o as REQUIRED_RECOMMENDATION_FIELDS,
|
|
30
|
-
l as RecommendationRequiredFieldsKey,
|
|
31
|
-
u as getInvalidFields,
|
|
32
|
-
s as isConfigValid
|
|
33
|
-
};
|