@useinsider/guido 3.3.0-beta.86ea9cd → 3.3.0-beta.8f029c7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/components/Guido.vue.js +1 -1
  2. package/dist/components/Guido.vue2.js +42 -40
  3. package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +9 -11
  4. package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +70 -35
  5. package/dist/components/organisms/header/MiddleSlot.vue.js +7 -7
  6. package/dist/composables/useCortexBlueprintBridge.js +66 -0
  7. package/dist/composables/useEmailTemplateApplier.js +41 -0
  8. package/dist/composables/useGuidoStateBridge.js +48 -0
  9. package/dist/composables/useHtmlValidator.js +41 -36
  10. package/dist/composables/useRecommendation.js +2 -2
  11. package/dist/config/migrator/radioButtonMigrator.js +30 -29
  12. package/dist/enums/extensions/recommendationBlock.js +101 -46
  13. package/dist/enums/unsubscribe.js +25 -24
  14. package/dist/extensions/Blocks/Checkbox/control.js +23 -23
  15. package/dist/extensions/Blocks/RadioButton/control.js +15 -15
  16. package/dist/extensions/Blocks/RadioButton/template.js +6 -6
  17. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +35 -26
  18. package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +25 -12
  19. package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +33 -0
  20. package/dist/guido.css +1 -1
  21. package/dist/package.json.js +1 -1
  22. package/dist/services/unsubscribeApi.js +6 -6
  23. package/dist/src/composables/useCortexBlueprintBridge.d.ts +25 -0
  24. package/dist/src/composables/useEmailTemplateApplier.d.ts +21 -0
  25. package/dist/src/composables/useGuidoStateBridge.d.ts +22 -0
  26. package/dist/src/enums/extensions/recommendationBlock.d.ts +6 -1
  27. package/dist/src/enums/unsubscribe.d.ts +8 -3
  28. package/dist/src/extensions/Blocks/RadioButton/template.d.ts +1 -1
  29. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +7 -1
  30. package/dist/src/extensions/Blocks/Recommendation/utils/filterUtil.d.ts +2 -0
  31. package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +21 -0
  32. package/dist/src/stores/guido-email-editor.d.ts +41 -0
  33. package/dist/stores/guido-email-editor.js +20 -0
  34. package/package.json +2 -2
@@ -1,11 +1,11 @@
1
- var d = Object.defineProperty;
2
- var l = (r, n, e) => n in r ? d(r, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[n] = e;
3
- var o = (r, n, e) => l(r, typeof n != "symbol" ? n + "" : n, e);
4
- import { useHttp as L } from "../../../composables/useHttp.js";
5
- import { DEFAULT_UNSUBSCRIBE_GROUP as c } from "../../../enums/unsubscribe.js";
6
- import { Control as h, UIElementType as i, UEAttr as t, ModificationDescription as p } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
- const m = "ui-elements-checkbox", u = "select", { get: C } = L();
8
- class S extends h {
1
+ var E = Object.defineProperty;
2
+ var d = (i, n, e) => n in i ? E(i, n, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[n] = e;
3
+ var o = (i, n, e) => d(i, typeof n != "symbol" ? n + "" : n, e);
4
+ import { useHttp as l } from "../../../composables/useHttp.js";
5
+ import { getDefaultUnsubscribeGroup as L, DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID as h } from "../../../enums/unsubscribe.js";
6
+ import { Control as p, UIElementType as r, UEAttr as t, ModificationDescription as m } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
+ const b = "ui-elements-checkbox", u = "select", { get: C } = l();
8
+ class I extends p {
9
9
  constructor() {
10
10
  super(...arguments);
11
11
  o(this, "currentNode");
@@ -13,13 +13,13 @@ class S extends h {
13
13
  o(this, "unsubList", []);
14
14
  }
15
15
  getId() {
16
- return m;
16
+ return b;
17
17
  }
18
18
  _setFormValues() {
19
19
  if (this.selectedUnsubGroup = "", this.currentNode && "getAttribute" in this.currentNode) {
20
20
  const e = this.currentNode.getAttribute("id");
21
21
  if (e) {
22
- const s = e === c.sendGridId ? e : Number(e);
22
+ const s = e === h ? e : Number(e);
23
23
  s && (this.selectedUnsubGroup = s);
24
24
  }
25
25
  }
@@ -29,18 +29,18 @@ class S extends h {
29
29
  }
30
30
  _getLabel(e, s = `${Math.random()}`) {
31
31
  return `
32
- <${i.LABEL}
32
+ <${r.LABEL}
33
33
  ${t.LABEL.text}="${e}"
34
34
  ${t.LABEL.name}="${s}">
35
- </${i.LABEL}>
35
+ </${r.LABEL}>
36
36
  `;
37
37
  }
38
38
  _getSelectItem(e, s) {
39
39
  return `
40
- <${i.SELECT_ITEM}
40
+ <${r.SELECT_ITEM}
41
41
  ${t.SELECT_ITEM.text}="${e}"
42
42
  ${t.SELECT_ITEM.value}="${s}">
43
- </${i.SELECT_ITEM}>`;
43
+ </${r.SELECT_ITEM}>`;
44
44
  }
45
45
  _getSelect() {
46
46
  return this.unsubList.map((e) => this._getSelectItem(e.name, e.sendGridId)).join("");
@@ -49,22 +49,22 @@ class S extends h {
49
49
  return `
50
50
  <div class="checkbox-controls-container">
51
51
  <div class="checkbox-select-container container two-columns stretch">
52
- <${i.LABEL}
52
+ <${r.LABEL}
53
53
  ${t.LABEL.text}="${this.api.translate("Unsubscribe Group")}"
54
54
  ${t.LABEL.name}="${Math.random()}">
55
- </${i.LABEL}>
55
+ </${r.LABEL}>
56
56
 
57
- <${i.SELECTPICKER}
57
+ <${r.SELECTPICKER}
58
58
  ${t.SELECTPICKER.name}="${u}"
59
59
  ${t.SELECTPICKER.placeholder}="${this.api.translate("Select Unsubscribe Group")}">
60
60
  ${this._getSelect()}
61
- </${i.SELECTPICKER}>
61
+ </${r.SELECTPICKER}>
62
62
  </div>
63
63
  </div>
64
64
  `;
65
65
  }
66
66
  _onSelectChange(e) {
67
- this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", e.toString()).apply(new p(`Updated text to ${e}`));
67
+ this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", e.toString()).apply(new m(`Updated text to ${e}`));
68
68
  }
69
69
  _listenToFormUpdates() {
70
70
  this.api.onValueChanged(u, (e) => this._onSelectChange(e));
@@ -76,18 +76,18 @@ class S extends h {
76
76
  async onRender() {
77
77
  const e = await C(
78
78
  "/unsubscribe-groups/unsubscribe-list"
79
- ), s = [c, ...e.data], E = s.map((a) => ({
79
+ ), s = [L(), ...e.data], c = s.map((a) => ({
80
80
  [t.SELECT_ITEM.text]: a.name,
81
81
  [t.SELECT_ITEM.value]: a.sendGridId
82
82
  }));
83
83
  this.unsubList = s, this.api.setUIEAttribute(
84
84
  u,
85
85
  t.SELECTPICKER.items,
86
- E
86
+ c
87
87
  ), this._setFormValues(), this._listenToFormUpdates();
88
88
  }
89
89
  }
90
90
  export {
91
- m as CHECKBOX_CONTROL_BLOCK_ID,
92
- S as CheckboxControl
91
+ b as CHECKBOX_CONTROL_BLOCK_ID,
92
+ I as CheckboxControl
93
93
  };
@@ -1,11 +1,11 @@
1
- var d = Object.defineProperty;
2
- var l = (r, n, t) => n in r ? d(r, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[n] = t;
3
- var o = (r, n, t) => l(r, typeof n != "symbol" ? n + "" : n, t);
4
- import { useHttp as L } from "../../../composables/useHttp.js";
5
- import { DEFAULT_UNSUBSCRIBE_GROUP as c } from "../../../enums/unsubscribe.js";
6
- import { Control as p, UIElementType as i, UEAttr as e, ModificationDescription as h } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
- const m = "ui-elements-radio-button", u = "select", { get: $ } = L();
8
- class S extends p {
1
+ var E = Object.defineProperty;
2
+ var d = (r, n, t) => n in r ? E(r, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[n] = t;
3
+ var o = (r, n, t) => d(r, typeof n != "symbol" ? n + "" : n, t);
4
+ import { useHttp as l } from "../../../composables/useHttp.js";
5
+ import { getDefaultUnsubscribeGroup as L, DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID as p } from "../../../enums/unsubscribe.js";
6
+ import { Control as h, UIElementType as i, UEAttr as e, ModificationDescription as m } from "../../../node_modules/@stripoinc/ui-editor-extensions/dist/esm/index.js";
7
+ const b = "ui-elements-radio-button", u = "select", { get: $ } = l();
8
+ class I extends h {
9
9
  constructor() {
10
10
  super(...arguments);
11
11
  o(this, "currentNode");
@@ -13,13 +13,13 @@ class S extends p {
13
13
  o(this, "unsubList", []);
14
14
  }
15
15
  getId() {
16
- return m;
16
+ return b;
17
17
  }
18
18
  _setFormValues() {
19
19
  if (this.selectedUnsubGroup = "", this.currentNode && "getAttribute" in this.currentNode) {
20
20
  const t = this.currentNode.getAttribute("id");
21
21
  if (t) {
22
- const s = t === c.sendGridId ? t : Number(t);
22
+ const s = t === p ? t : Number(t);
23
23
  s && (this.selectedUnsubGroup = s);
24
24
  }
25
25
  }
@@ -64,7 +64,7 @@ class S extends p {
64
64
  `;
65
65
  }
66
66
  _onSelectChange(t) {
67
- this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", t.toString()).apply(new h(`Updated text to ${t}`));
67
+ this.currentNode && this.api.getDocumentModifier().modifyHtml(this.currentNode).setAttribute("id", t.toString()).apply(new m(`Updated text to ${t}`));
68
68
  }
69
69
  _listenToFormUpdates() {
70
70
  this.api.onValueChanged(u, (t) => this._onSelectChange(t));
@@ -76,18 +76,18 @@ class S extends p {
76
76
  async onRender() {
77
77
  const t = await $(
78
78
  "/unsubscribe-groups/unsubscribe-list"
79
- ), s = [c, ...t.data], E = s.map((a) => ({
79
+ ), s = [L(), ...t.data], c = s.map((a) => ({
80
80
  [e.SELECT_ITEM.text]: a.name,
81
81
  [e.SELECT_ITEM.value]: a.sendGridId
82
82
  }));
83
83
  this.unsubList = s, this.api.setUIEAttribute(
84
84
  u,
85
85
  e.SELECTPICKER.items,
86
- E
86
+ c
87
87
  ), this._setFormValues(), this._listenToFormUpdates();
88
88
  }
89
89
  }
90
90
  export {
91
- m as CONTROL_BLOCK_ID,
92
- S as RadioButtonControl
91
+ b as CONTROL_BLOCK_ID,
92
+ I as RadioButtonControl
93
93
  };
@@ -5,7 +5,7 @@ const e = {
5
5
  YES: "Yes",
6
6
  NO: "No"
7
7
  }, d = `
8
- <td align="left" class="radio-button radio-button-v2 esd-block-radio es-p10t es-p10b es-p30r es-p30l">
8
+ <td align="left" class="radio-button-block radio-button-v2 esd-block-radio es-p10t es-p10b es-p30r es-p30l">
9
9
  <table cellpadding="0" cellspacing="0" role="presentation" width="100%">
10
10
  <tbody>
11
11
  <tr>
@@ -75,13 +75,13 @@ const e = {
75
75
  </tbody>
76
76
  </table>
77
77
  </td>
78
- `, a = `
78
+ `, l = `
79
79
  <td
80
80
  align="left"
81
81
  esd-extension-block-id="radio-button-block"
82
82
  esd-handler-name="esd-extension-RadioButtonBlock"
83
83
  class="
84
- radio-button
84
+ radio-button-block
85
85
  radio-button-v2
86
86
  esd-block-ra
87
87
  esd-radio-button-block
@@ -149,10 +149,10 @@ const e = {
149
149
  </table>
150
150
  </td>
151
151
  `;
152
- function l() {
152
+ function a() {
153
153
  return d.replace("{-{-TITLE-}-}", `<p path="1">${e.TITLE}</p>`).replace("{-{-DESCRIPTION-}-}", `<p path="1">${e.DESCRIPTION}</p>`).replace("{-{-YES-}-}", `<p path="1">${e.YES}</p>`).replace("{-{-NO-}-}", `<p path="1">${e.NO}</p>`);
154
154
  }
155
155
  export {
156
- a as default,
157
- l as getDefaultTemplate
156
+ l as default,
157
+ a as getDefaultTemplate
158
158
  };
@@ -1,14 +1,15 @@
1
- import { RecommendationFeedSourceMaps as S, getOperatorOptions as R, PriceAttributes as y } from "../../../../enums/extensions/recommendationBlock.js";
1
+ import { getRecommendationFeedSourceMaps as g, 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 g } from "../templates/utils.js";
7
+ import { getDefaultProducts as S } 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";
10
11
  const h = C();
11
- let u = null, m = null, d = null;
12
+ let m = null, u = null, d = null;
12
13
  function k() {
13
14
  return {
14
15
  cardsInRow: F,
@@ -48,7 +49,7 @@ function I() {
48
49
  filterSnapshot: null
49
50
  };
50
51
  }
51
- const v = () => ({
52
+ const N = () => ({
52
53
  recommendationCampaignUrls: {},
53
54
  activePredictiveAlgorithms: [],
54
55
  languages: {},
@@ -57,8 +58,8 @@ const v = () => ({
57
58
  blockStates: {},
58
59
  currentRecommendationId: null,
59
60
  configVersion: 0
60
- }), _ = P("guidoRecommendationExtension", {
61
- state: () => v(),
61
+ }), M = P("guidoRecommendationExtension", {
62
+ state: () => N(),
62
63
  getters: {
63
64
  // ====================================================================
64
65
  // Proxy Getters — Backward Compatible Access to Current Block State
@@ -113,12 +114,12 @@ const v = () => ({
113
114
  return [...new Set(t.map((e) => e.filterGroup))].sort((e, r) => e - r);
114
115
  },
115
116
  getActivePredictiveAlgorithms: (t) => {
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
117
+ const e = g(), r = [];
118
+ return t.activePredictiveAlgorithms.filter((n) => !D.includes(n)).forEach((n) => {
119
+ r.push(...e.filter((c) => c.id === n));
120
+ }), r.map((n) => ({
121
+ text: n.name,
122
+ value: n.key
122
123
  }));
123
124
  },
124
125
  getLanguages: (t) => Object.entries(t.languages).map(([e, r]) => ({
@@ -293,11 +294,11 @@ const v = () => ({
293
294
  // ====================================================================
294
295
  async fetchRecommendationCreateData() {
295
296
  if (!this.activePredictiveAlgorithms.length) {
296
- if (u) {
297
- await u;
297
+ if (m) {
298
+ await m;
298
299
  return;
299
300
  }
300
- u = (async () => {
301
+ m = (async () => {
301
302
  const {
302
303
  activePredictiveAlgorithms: t,
303
304
  languages: e,
@@ -310,26 +311,26 @@ const v = () => ({
310
311
  this.currencyList = r;
311
312
  })();
312
313
  try {
313
- await u;
314
+ await m;
314
315
  } finally {
315
- u = null;
316
+ m = null;
316
317
  }
317
318
  }
318
319
  },
319
320
  async fetchRecommendationFilters() {
320
321
  if (!Object.keys(this.filterList).length) {
321
- if (m) {
322
- await m;
322
+ if (u) {
323
+ await u;
323
324
  return;
324
325
  }
325
- m = (async () => {
326
+ u = (async () => {
326
327
  const t = await h.fetchRecommendationFilters();
327
328
  this.filterList = t;
328
329
  })();
329
330
  try {
330
- await m;
331
+ await u;
331
332
  } finally {
332
- m = null;
333
+ u = null;
333
334
  }
334
335
  }
335
336
  },
@@ -398,6 +399,14 @@ const v = () => ({
398
399
  generateFilterQuery() {
399
400
  return b(this.recommendationConfigs.filters);
400
401
  },
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
+ },
401
410
  // ====================================================================
402
411
  // Per-Block Product Fetching
403
412
  // ====================================================================
@@ -417,7 +426,7 @@ const v = () => ({
417
426
  },
418
427
  async _doFetchProducts() {
419
428
  var 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 = {
429
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = r.filters.filter((l) => l.isValid), c = b(n), i = ((p = g().find((l) => l.key === r.strategy)) == null ? void 0 : p.path) || "", o = G(), s = parseInt(r.size) || 6, a = {
421
430
  locale: r.language,
422
431
  currency: r.currencySettings.value,
423
432
  partnerName: o.partnerName,
@@ -433,15 +442,15 @@ const v = () => ({
433
442
  f = [];
434
443
  }
435
444
  if (this.blockStates[t]) {
436
- const l = f.length > 0 ? f : g(s);
445
+ const l = f.length > 0 ? f : S(s);
437
446
  l.length < s ? this.blockStates[t].recommendationProducts = [
438
447
  ...l,
439
- ...g(s - l.length)
448
+ ...S(s - l.length)
440
449
  ] : l.length > s ? this.blockStates[t].recommendationProducts = l.slice(0, s) : this.blockStates[t].recommendationProducts = l;
441
450
  }
442
451
  }
443
452
  }
444
453
  });
445
454
  export {
446
- _ as useRecommendationExtensionStore
455
+ M as useRecommendationExtensionStore
447
456
  };
@@ -1,31 +1,44 @@
1
- function l(t) {
1
+ import { OP_ANY_OF as l } from "../../../../enums/extensions/recommendationBlock.js";
2
+ function m(t) {
3
+ try {
4
+ return decodeURIComponent(t);
5
+ } catch {
6
+ return t;
7
+ }
8
+ }
9
+ function f(t) {
10
+ return t.split(",").filter(Boolean).map(m);
11
+ }
12
+ function y(t) {
2
13
  if (t.length === 0)
3
14
  return "";
4
15
  const o = t.sort((r, e) => r.filterNumber - e.filterNumber), u = o.map((r) => {
5
- const e = r.operator === "||", a = e ? "=" : r.operator, c = e ? decodeURIComponent(r.value).split(",").join("||") : r.value;
16
+ const e = r.operator === l, a = e ? "=" : r.operator, c = e ? f(r.value).join(l) : r.value;
6
17
  return `[${r.attribute}][${a}][${c}]`;
7
- }), [s, ...p] = u;
8
- let n = s;
18
+ }), [i, ...p] = u;
19
+ let n = i;
9
20
  for (let r = 0; r < p.length; r++) {
10
21
  const e = o[r].innerGroupOperator;
11
22
  n += `${e}${p[r]}`;
12
23
  }
13
24
  return `(${n})`;
14
25
  }
15
- function G(t) {
26
+ function Q(t) {
16
27
  if (!t || t.length === 0)
17
28
  return "";
18
- const o = t.reduce((r, e) => (r[e.filterGroup] || (r[e.filterGroup] = []), r[e.filterGroup].push(e), r), {}), u = Object.keys(o).map(Number).sort((r, e) => r - e), s = u.map((r) => {
29
+ const o = t.reduce((r, e) => (r[e.filterGroup] || (r[e.filterGroup] = []), r[e.filterGroup].push(e), r), {}), u = Object.keys(o).map(Number).sort((r, e) => r - e), i = u.map((r) => {
19
30
  const e = o[r];
20
- return l(e);
21
- }), [p, ...n] = s;
22
- let i = p;
31
+ return y(e);
32
+ }), [p, ...n] = i;
33
+ let s = p;
23
34
  for (let r = 0; r < n.length; r++) {
24
35
  const e = u[r + 1], c = o[e][0].outerGroupOperator;
25
- i += `${c}${n[r]}`;
36
+ s += `${c}${n[r]}`;
26
37
  }
27
- return i.trim();
38
+ return s.trim();
28
39
  }
29
40
  export {
30
- G as generateCompleteFilterQuery
41
+ Q as generateCompleteFilterQuery,
42
+ f as parseTagList,
43
+ m as safeDecodeURIComponent
31
44
  };
@@ -0,0 +1,33 @@
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
+ };
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-1a4e7084]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-1a4e7084]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-1a4e7084]{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}
1
+ .gap-16[data-v-8053a037],.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-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}
@@ -1,4 +1,4 @@
1
- const o = { stripo: { version: "2.62.0" } }, s = {
1
+ const o = { stripo: { version: "2.64.0" } }, s = {
2
2
  guido: o
3
3
  };
4
4
  export {
@@ -1,13 +1,13 @@
1
1
  import { useHttp as t } from "../composables/useHttp.js";
2
- import { useToaster as n } from "../composables/useToaster.js";
2
+ import { useToaster as a } from "../composables/useToaster.js";
3
3
  const u = () => {
4
- const { get: r } = t(), { handleError: s } = n();
4
+ const { get: e } = t(), { handleError: s } = a();
5
5
  return { getUnsubscribePages: async () => {
6
6
  try {
7
- const { data: e = [] } = await r("/unsubscribe-pages/get-all");
8
- return e;
9
- } catch (e) {
10
- return s(e, "Failed to fetch unsubscribe pages"), [];
7
+ const { data: r } = await e("/unsubscribe-pages/get-all");
8
+ return Array.isArray(r) ? r : [];
9
+ } catch (r) {
10
+ return s(r, "Failed to fetch unsubscribe pages"), [];
11
11
  }
12
12
  } };
13
13
  };
@@ -0,0 +1,25 @@
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 two 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
+ * - `error` segments (and message-level `isError` / `isCancelled`) trigger
15
+ * a localized toaster.
16
+ *
17
+ * In dev (`import.meta.env.DEV`) every observed segment + message-level flag
18
+ * change is also `console.debug`-logged with the prefix `[guido:cortex]` so a
19
+ * developer can watch the agent stream in real time. In production this is
20
+ * gated behind `localStorage.guido:debug:ai === '1'`.
21
+ *
22
+ * If cortex-fe isn't loaded the chat store is undefined and the bridge is a
23
+ * no-op (intentional — Guido must still work standalone).
24
+ */
25
+ 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,16 @@ export declare const URLS: {
6
6
  export declare const QUERY_PARAMS: {
7
7
  CLIENT_ID: string;
8
8
  };
9
- export declare const RecommendationFeedSourceMaps: RecommendationFeedItem[];
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[];
10
14
  export declare const PriceAttributes: string[];
11
15
  export declare const currencyLocationMaps: TextValueObject[];
12
16
  export declare const currencyOperators: TextValueObject[];
13
17
  export declare const currencyDecimalCounts: TextValueObject[];
18
+ export declare const OP_ANY_OF = "||";
14
19
  export declare const operatorOptionsForStrings: TextValueObject[];
15
20
  export declare const operatorOptionsForArrayOfStrings: TextValueObject[];
16
21
  export declare const operatorOptionsForNumbers: TextValueObject[];
@@ -18,9 +18,14 @@ 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 DEFAULT_UNSUBSCRIBE_GROUP: {
22
- readonly name: "Global Unsubscribe";
23
- readonly sendGridId: "G";
21
+ export declare const DEFAULT_UNSUBSCRIBE_GROUP_SEND_GRID_ID = "G";
22
+ /**
23
+ * Get the default unsubscribe group lazily so the translated name resolves at access time.
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;
24
29
  };
25
30
  export declare const UNSUBSCRIBE_PAGES_LINK = "/email/unsubscribe-pages";
26
31
  export declare const PAGE_TYPES: {
@@ -1,4 +1,4 @@
1
- declare const migrationTemplate = "\n <td\n align=\"left\"\n esd-extension-block-id=\"radio-button-block\"\n esd-handler-name=\"esd-extension-RadioButtonBlock\"\n class=\"\n radio-button\n radio-button-v2\n esd-block-ra\n esd-radio-button-block\n esd-extension-block\n es-p10t\n es-p10b\n es-p30r\n es-p30l\"\n >\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td align=\"left\" width=\"70%\" style=\"vertical-align: top;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n {-{-TITLE-}-}\n </tr>\n <tr>\n {-{-DESCRIPTION-}-}\n </tr>\n </tbody>\n </table>\n </td>\n <td align=\"right\" width=\"30%\" style=\"vertical-align: middle;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioYes\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-YES-}-}\n </tr>\n </table>\n </td>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioNo\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-NO-}-}\n </tr>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n";
1
+ declare const migrationTemplate = "\n <td\n align=\"left\"\n esd-extension-block-id=\"radio-button-block\"\n esd-handler-name=\"esd-extension-RadioButtonBlock\"\n class=\"\n radio-button-block\n radio-button-v2\n esd-block-ra\n esd-radio-button-block\n esd-extension-block\n es-p10t\n es-p10b\n es-p30r\n es-p30l\"\n >\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td align=\"left\" width=\"70%\" style=\"vertical-align: top;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n {-{-TITLE-}-}\n </tr>\n <tr>\n {-{-DESCRIPTION-}-}\n </tr>\n </tbody>\n </table>\n </td>\n <td align=\"right\" width=\"30%\" style=\"vertical-align: middle;\">\n <table cellpadding=\"0\" cellspacing=\"0\" role=\"presentation\" width=\"100%\">\n <tbody>\n <tr>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioYes\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-YES-}-}\n </tr>\n </table>\n </td>\n <td width=\"50%\">\n <table width=\"100%\">\n <tr>\n <td width=\"24\">\n <input\n type=\"radio\"\n id=\"radioNo\"\n name=\"unsubscribe\"\n data-cke-editable=\"1\"\n style=\"margin: 0px; vertical-align: middle;\">\n </td>\n {-{-NO-}-}\n </tr>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n </tr>\n </tbody>\n </table>\n </td>\n";
2
2
  /**
3
3
  * @returns The template for the default checkbox block
4
4
  */