@useinsider/guido 3.19.0-beta.c8d2be8 → 3.19.0-beta.cac604e

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 (26) hide show
  1. package/dist/@types/config/schemas.js +104 -91
  2. package/dist/components/organisms/header/EditorActions.vue.js +4 -4
  3. package/dist/components/organisms/header/EditorActions.vue2.js +23 -25
  4. package/dist/composables/useActionsApi.js +52 -47
  5. package/dist/composables/useCodeEditorApi.js +23 -9
  6. package/dist/composables/useHttp.js +44 -55
  7. package/dist/composables/useTranslations.js +3 -2
  8. package/dist/composables/useVersionHistoryApi.js +33 -24
  9. package/dist/extensions/Blocks/Recommendation/block.js +88 -53
  10. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +45 -38
  11. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +72 -49
  12. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +42 -22
  13. package/dist/extensions/Blocks/Recommendation/utils/partnerScope.js +26 -0
  14. package/dist/guido.css +1 -1
  15. package/dist/src/@types/config/schemas.d.ts +16 -0
  16. package/dist/src/composables/useConfig.d.ts +2 -0
  17. package/dist/src/extensions/Blocks/Recommendation/block.d.ts +6 -0
  18. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +5 -0
  19. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +6 -0
  20. package/dist/src/extensions/Blocks/Recommendation/utils/partnerScope.d.ts +27 -0
  21. package/dist/src/stores/config.d.ts +20 -0
  22. package/dist/src/utils/stripoEditorApi.d.ts +4 -0
  23. package/dist/static/styles/components/recommendation-strategy.css.js +9 -0
  24. package/dist/stores/unsubscribe.js +3 -3
  25. package/dist/utils/stripoEditorApi.js +11 -0
  26. package/package.json +2 -1
@@ -1,33 +1,35 @@
1
- var C = Object.defineProperty;
2
- var $ = (c, n, t) => n in c ? C(c, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[n] = t;
3
- var i = (c, n, t) => $(c, typeof n != "symbol" ? n + "" : n, t);
4
- import { useLegacyStrategyConversion as k } from "../../../../../composables/useLegacyStrategyConversion.js";
5
- import { ACADEMY_LINKS as L } from "../../../../../enums/academy.js";
6
- import { useOnboardingStore as w } from "../../../../../stores/onboarding.js";
7
- import { CommonControl as A } from "../../../common-control.js";
8
- import { RRS_CONFIG_VERSION as N } from "../../constants/defaultConfig.js";
9
- import { RecommendationConfigService as b } from "../../services/configService.js";
10
- import { useRecommendationExtensionStore as R } from "../../store/recommendation.js";
11
- const E = "recommendation-strategy-control";
12
- class M extends A {
1
+ var w = Object.defineProperty;
2
+ var N = (l, o, t) => o in l ? w(l, o, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[o] = t;
3
+ var i = (l, o, t) => N(l, typeof o != "symbol" ? o + "" : o, t);
4
+ import { useLegacyStrategyConversion as L } from "../../../../../composables/useLegacyStrategyConversion.js";
5
+ import { ACADEMY_LINKS as $ } from "../../../../../enums/academy.js";
6
+ import { useOnboardingStore as A } from "../../../../../stores/onboarding.js";
7
+ import { CommonControl as R } from "../../../common-control.js";
8
+ import { RRS_CONFIG_VERSION as E } from "../../constants/defaultConfig.js";
9
+ import { RecommendationConfigService as C } from "../../services/configService.js";
10
+ import { useRecommendationExtensionStore as O } from "../../store/recommendation.js";
11
+ const I = "recommendation-strategy-control";
12
+ class P extends R {
13
13
  constructor() {
14
14
  super(...arguments);
15
- i(this, "store", R());
16
- i(this, "onboardingStore", w());
17
- i(this, "legacyConversion", k());
15
+ i(this, "store", O());
16
+ i(this, "onboardingStore", A());
17
+ i(this, "legacyConversion", L());
18
18
  i(this, "storeUnsubscription", () => {
19
19
  });
20
20
  i(this, "listeners", []);
21
21
  i(this, "lastPaintedState", null);
22
22
  }
23
23
  getId() {
24
- return E;
24
+ return I;
25
25
  }
26
26
  getTemplate() {
27
27
  const t = this.api.translate(
28
28
  "You can assign a recommendation strategy by selecting an existing one or creating a new one to show specific content."
29
- ), e = this.api.translate("For more information, you can"), s = this.api.translate("visit Academy"), o = this.api.translate("Legacy Strategy"), a = this.api.translate(
29
+ ), e = this.api.translate("For more information, you can"), a = this.api.translate("visit Academy"), r = this.api.translate("Legacy Strategy"), s = this.api.translate(
30
30
  "Note that this is an older version of the Recommendation Strategy. We recommend you update it to the new Recommendation Strategy for an improved experience."
31
+ ), g = this.api.translate(
32
+ "The recommendation strategy used in the recommendation block is no longer available. You can assign a different strategy to it."
31
33
  );
32
34
  return `
33
35
  <div class="strategy-control-container">
@@ -52,9 +54,9 @@ class M extends A {
52
54
  ${t}
53
55
  ${e}
54
56
  <a
55
- href="${L.EMAIL_RECOMMENDATION_BLOCK}"
57
+ href="${$.EMAIL_RECOMMENDATION_BLOCK}"
56
58
  target="_blank"
57
- rel="noopener noreferrer">${s}</a>.
59
+ rel="noopener noreferrer">${a}</a>.
58
60
  </p>
59
61
  </div>
60
62
  <div data-strategy-empty-state style="display: none;">
@@ -71,16 +73,37 @@ class M extends A {
71
73
  id: "guido__btn-create-strategy",
72
74
  className: "strategy-control-cta primary"
73
75
  })
76
+ ], "strategy-control-cta-row")}
77
+ </div>
78
+ <div data-strategy-unavailable-state style="display: none;">
79
+ <div class="strategy-control-notice-row">
80
+ <div class="strategy-control-notice strategy-control-notice--error" role="alert">
81
+ <p class="strategy-control-notice-text">${g}</p>
82
+ </div>
83
+ </div>
84
+ ${this._GuTwoColumns([
85
+ this._GuButton({
86
+ name: "assignUnavailableStrategy",
87
+ label: this.api.translate("Assign Strategy"),
88
+ id: "guido__btn-assign-unavailable-strategy",
89
+ className: "strategy-control-cta on"
90
+ }),
91
+ this._GuButton({
92
+ name: "createUnavailableStrategy",
93
+ label: this.api.translate("Create New Strategy"),
94
+ id: "guido__btn-create-unavailable-strategy",
95
+ className: "strategy-control-cta primary"
96
+ })
74
97
  ], "strategy-control-cta-row")}
75
98
  </div>
76
99
  <div data-strategy-legacy-state style="display: none;">
77
100
  <div class="strategy-control-notice-row">
78
101
  <div class="strategy-control-notice">
79
- <p class="strategy-control-notice-text">${a}</p>
102
+ <p class="strategy-control-notice-text">${s}</p>
80
103
  </div>
81
104
  </div>
82
105
  <div class="strategy-control-name-band">
83
- <span class="strategy-control-name">${o}</span>
106
+ <span class="strategy-control-name">${r}</span>
84
107
  ${this._strategyAction({
85
108
  id: "guido__btn-update-legacy-strategy",
86
109
  label: this.api.translate("Update"),
@@ -123,12 +146,12 @@ class M extends A {
123
146
  </div>
124
147
  `;
125
148
  }
126
- _strategyAction({ id: t, label: e, modifier: s }) {
149
+ _strategyAction({ id: t, label: e, modifier: a }) {
127
150
  return `
128
151
  <button
129
152
  id="${t}"
130
153
  type="button"
131
- class="strategy-control-action strategy-control-action--${s}">
154
+ class="strategy-control-action strategy-control-action--${a}">
132
155
  <span>${e}</span>
133
156
  </button>
134
157
  `;
@@ -136,8 +159,8 @@ class M extends A {
136
159
  onRender() {
137
160
  this._teardown(), this.store.strategyPanelOpen = !0, this._setupButtonListeners(), this._renderState(), this.storeUnsubscription = this.store.$subscribe(() => {
138
161
  this._renderState();
139
- }), this.store.recommendationConfigs.strategyId && !this.store.strategiesFetched && this.store.fetchStrategies().catch(() => {
140
- });
162
+ }), this.store.recommendationConfigs.strategyId && !this.store.strategiesLoading && (this.store.invalidateStrategies(), this.store.fetchStrategies().catch(() => {
163
+ }));
141
164
  }
142
165
  /**
143
166
  * Whether the document itself says this block has no strategy.
@@ -147,10 +170,10 @@ class M extends A {
147
170
  * strategyId) for an assigned block.
148
171
  */
149
172
  _isNodeUnassigned() {
150
- if (!b.hasConfig(this.currentNode))
173
+ if (!C.hasConfig(this.currentNode))
151
174
  return !1;
152
- const t = b.getConfig(this.currentNode);
153
- return !t.strategyId && (t.configVersion ?? 0) >= N;
175
+ const t = C.getConfig(this.currentNode);
176
+ return !t.strategyId && (t.configVersion ?? 0) >= E;
154
177
  }
155
178
  onDestroy() {
156
179
  this._teardown();
@@ -163,37 +186,37 @@ class M extends A {
163
186
  const t = this.getContainer();
164
187
  if (!t)
165
188
  return;
166
- const e = (s, o) => {
167
- const a = t.querySelector(s);
168
- a && (a.addEventListener("click", o), this.listeners.push({ element: a, handler: o }));
189
+ const e = (a, r) => {
190
+ const s = t.querySelector(a);
191
+ s && (s.addEventListener("click", r), this.listeners.push({ element: s, handler: r }));
169
192
  };
170
- e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-create-strategy", () => this.store.openStrategyCreation()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-legacy-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal()), e("#guido__btn-remove-legacy-strategy", () => this.store.openRemoveStrategyModal()), e("#guido__btn-update-legacy-strategy", () => {
193
+ e("#guido__btn-assign-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-create-strategy", () => this.store.openStrategyCreation()), e("#guido__btn-assign-unavailable-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-create-unavailable-strategy", () => this.store.openStrategyCreation()), e("#guido__btn-change-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-change-legacy-strategy", () => this.store.openAssignStrategyDrawer()), e("#guido__btn-remove-strategy", () => this.store.openRemoveStrategyModal()), e("#guido__btn-remove-legacy-strategy", () => this.store.openRemoveStrategyModal()), e("#guido__btn-update-legacy-strategy", () => {
171
194
  this.legacyConversion.convertLegacyStrategy();
172
195
  });
173
196
  }
174
197
  _renderState() {
175
- var _;
176
- const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((_ = this.store.assignedStrategy) == null ? void 0 : _.name) ?? "" : "", s = !!t && !e && (this.store.strategiesLoading || !this.store.strategiesSettled), o = this.store.legacyConversionLoading, a = this.store.isLegacyStrategyBlock, h = `${t}\0${e}\0${s}\0${o}\0${a}`;
177
- if (h === this.lastPaintedState)
198
+ var f;
199
+ const { strategyId: t } = this.store.recommendationConfigs, e = t ? ((f = this.store.assignedStrategy) == null ? void 0 : f.name) ?? "" : "", a = !!t && !e && (this.store.strategiesLoading || !this.store.strategiesSettled), r = !!t && !e && !a && this.store.strategiesFetched, s = this.store.legacyConversionLoading, g = this.store.isLegacyStrategyBlock, p = [t, e, a, r, s, g].join("\0");
200
+ if (p === this.lastPaintedState)
178
201
  return;
179
- const r = this.getContainer();
180
- if (!r)
202
+ const n = this.getContainer();
203
+ if (!n)
181
204
  return;
182
- const d = r.querySelector("[data-strategy-empty-state]"), y = r.querySelector("[data-strategy-assigned-state]"), g = r.querySelector("[data-strategy-legacy-state]"), p = r.querySelector("[data-strategy-loading-state]"), u = r.querySelector("[data-strategy-content]"), m = r.querySelector("[data-strategy-name]"), v = r.querySelector("[data-strategy-name-skeleton]");
183
- if (!d || !y || !g)
205
+ const y = n.querySelector("[data-strategy-empty-state]"), u = n.querySelector("[data-strategy-assigned-state]"), c = n.querySelector("[data-strategy-legacy-state]"), h = n.querySelector("[data-strategy-unavailable-state]"), v = n.querySelector("[data-strategy-loading-state]"), b = n.querySelector("[data-strategy-content]"), m = n.querySelector("[data-strategy-name]"), _ = n.querySelector("[data-strategy-name-skeleton]");
206
+ if (!y || !u || !c || !h)
184
207
  return;
185
- p && (p.style.display = "none"), u && (u.style.display = "");
186
- const f = t ? y : a ? g : d;
187
- [d, y, g].forEach((l) => {
188
- l.style.display = l === f ? "" : "none";
189
- }), g.querySelectorAll("button").forEach((l) => {
190
- l.disabled = o;
191
- }), g.classList.toggle("is-converting", o), !t && this._isNodeUnassigned() && this.onboardingStore.startOnboarding("recommendationStrategyOnboarding");
208
+ v && (v.style.display = "none"), b && (b.style.display = "");
209
+ const k = t ? r ? h : u : g ? c : y;
210
+ [y, u, c, h].forEach((d) => {
211
+ d.style.display = d === k ? "" : "none";
212
+ }), c.querySelectorAll("button").forEach((d) => {
213
+ d.disabled = s;
214
+ }), c.classList.toggle("is-converting", s), !t && this._isNodeUnassigned() && this.onboardingStore.startOnboarding("recommendationStrategyOnboarding");
192
215
  const S = this.store.currentRecommendationId;
193
- a && S !== null && this.store.blockStates[S] && this.onboardingStore.startOnboarding("recommendationLegacyStrategyOnboarding"), m && (m.style.display = s ? "none" : "", t && !s && (m.textContent = e || `#${t}`)), v && (v.style.display = s ? "block" : "none"), this.lastPaintedState = h;
216
+ g && S !== null && this.store.blockStates[S] && this.onboardingStore.startOnboarding("recommendationLegacyStrategyOnboarding"), m && (m.style.display = a ? "none" : "", t && !a && (m.textContent = e || `#${t}`)), _ && (_.style.display = a ? "block" : "none"), this.lastPaintedState = p;
194
217
  }
195
218
  }
196
219
  export {
197
- E as STRATEGY_CONTROL_ID,
198
- M as StrategyControl
220
+ I as STRATEGY_CONTROL_ID,
221
+ P as StrategyControl
199
222
  };
@@ -3,7 +3,7 @@ import { useTranslations as L } from "../../../../composables/useTranslations.js
3
3
  import { getRecommendationFeedSourceMaps as F, strategyEditPath as U, URLS as E, getOperatorOptions as N, PriceAttributes as M } from "../../../../enums/extensions/recommendationBlock.js";
4
4
  import { ToasterTypeOptions as A } from "../../../../enums/toaster.js";
5
5
  import { useRecommendationApi as T } from "../../../../services/recommendationApi.js";
6
- import { useConfigStore as k } from "../../../../stores/config.js";
6
+ import { useConfigStore as R } from "../../../../stores/config.js";
7
7
  import { defineStore as B } from "pinia";
8
8
  import "../constants/selectors.js";
9
9
  import { DEFAULT_MOBILE_CARDS_IN_ROW as O, DEFAULT_CARDS_IN_ROW as z } from "../constants/layout.js";
@@ -12,11 +12,11 @@ import { getDefaultProducts as w } from "../templates/utils.js";
12
12
  import { generateCompleteFilterQuery as P } from "../utils/filterUtil.js";
13
13
  import { isLegacyStrategyConfig as j } from "../utils/legacyStrategyMigration.js";
14
14
  import { getPartnerRecommendationParams as $ } from "../utils/partnerCustomizations.js";
15
- import { sanitizeProductIds as q } from "../utils/productIds.js";
16
- import { isFilterValid as K } from "../validation/filterSchema.js";
15
+ import { sanitizeProductIds as K } from "../utils/productIds.js";
16
+ import { isFilterValid as q } from "../validation/filterSchema.js";
17
17
  import { getInvalidFields as H, isConfigValid as J } from "../validation/requiredFields.js";
18
18
  const m = T();
19
- let S = null, p = null, y = null, I = "", R = null, b = 0;
19
+ let S = null, p = null, y = null, b = "", k = null, I = 0;
20
20
  const g = /* @__PURE__ */ new Map();
21
21
  let l = null;
22
22
  function _() {
@@ -45,7 +45,7 @@ function _() {
45
45
  // that default is what reached buildCampaignUrl and baked a most-popular feed URL
46
46
  // for a block the user never configured (SD-149916). Legacy blocks still get their real
47
47
  // algorithm from the node-config sync or the save-time seed.
48
- strategy: k().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
48
+ strategy: R().isFeatureEnabled("reusableRecommendationStrategy") ? "" : "mostPopular",
49
49
  strategyId: "",
50
50
  nodeConfigVersion: C,
51
51
  textTrimming: !0,
@@ -119,7 +119,7 @@ const Q = () => ({
119
119
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].removeStrategyModalStatus : !1;
120
120
  },
121
121
  isLegacyStrategyBlock() {
122
- return k().isFeatureEnabled("reusableRecommendationStrategy") && j(this.recommendationConfigs);
122
+ return R().isFeatureEnabled("reusableRecommendationStrategy") && j(this.recommendationConfigs);
123
123
  },
124
124
  legacyConversionLoading(t) {
125
125
  return t.currentRecommendationId !== null && t.blockStates[t.currentRecommendationId] ? t.blockStates[t.currentRecommendationId].legacyConversionLoading ?? !1 : !1;
@@ -234,7 +234,7 @@ const Q = () => ({
234
234
  const r = this.blockStates[t];
235
235
  if (r) {
236
236
  const o = structuredClone(r);
237
- o.recommendationConfigs.id = e, o.recommendationConfigs.strategyId && k().isFeatureEnabled("reusableRecommendationStrategy") && (o.isInitialized = !1, o.syncedConfigFingerprint = null), this.blockStates = {
237
+ o.recommendationConfigs.id = e, o.recommendationConfigs.strategyId && R().isFeatureEnabled("reusableRecommendationStrategy") && (o.isInitialized = !1, o.syncedConfigFingerprint = null), this.blockStates = {
238
238
  ...this.blockStates,
239
239
  [e]: o
240
240
  };
@@ -380,31 +380,50 @@ const Q = () => ({
380
380
  this.currentRecommendationId === null || !this.blockStates[this.currentRecommendationId] || (this.blockStates[this.currentRecommendationId].removeStrategyModalStatus = !1);
381
381
  },
382
382
  async fetchStrategies() {
383
- for (; R; )
383
+ for (; k; )
384
384
  try {
385
- await R;
385
+ await k;
386
386
  } catch {
387
387
  }
388
388
  if (this.strategiesFetched)
389
389
  return;
390
- const t = b, e = (async () => {
390
+ const t = I, e = (async () => {
391
391
  this.strategiesLoading = !0;
392
392
  try {
393
393
  const r = await m.fetchRecommendationStrategies();
394
- if (t !== b)
394
+ if (t !== I)
395
395
  return;
396
396
  this.strategies = r, this.strategiesFetched = !0;
397
397
  } finally {
398
- this.strategiesLoading = !1, t === b && (this.strategiesSettled = !0);
398
+ this.strategiesLoading = !1, t === I && (this.strategiesSettled = !0);
399
399
  }
400
400
  })();
401
- R = e;
401
+ k = e;
402
402
  try {
403
403
  await e;
404
404
  } finally {
405
- R = null;
405
+ k = null;
406
406
  }
407
407
  },
408
+ /**
409
+ * Drops what the store still holds for a block whose account-scoped config was just
410
+ * reset in the document (SD-151945), so the panel re-seeds from the emptied node.
411
+ */
412
+ resetPartnerScopedConfig(t) {
413
+ const e = t.toString();
414
+ if (this.recommendationCampaignUrls[e] !== void 0) {
415
+ const n = { ...this.recommendationCampaignUrls };
416
+ delete n[e], this.recommendationCampaignUrls = n;
417
+ }
418
+ const r = this.blockStates[t];
419
+ r && (r.recommendationConfigs = {
420
+ ...r.recommendationConfigs,
421
+ strategyId: "",
422
+ strategy: "",
423
+ filters: [],
424
+ productIds: []
425
+ }, r.isInitialized = !1, r.syncedConfigFingerprint = null, this.currentRecommendationId === t && this.configVersion++);
426
+ },
408
427
  /**
409
428
  * Clears what a block inherited from the id it arrived holding, so the panel fetches for it.
410
429
  * A re-dropped saved module can keep the source's id — and its "already fetched" entry —
@@ -416,7 +435,7 @@ const Q = () => ({
416
435
  }));
417
436
  },
418
437
  invalidateStrategies() {
419
- this.strategiesFetched = !1, this.strategiesSettled = !1, b += 1;
438
+ this.strategiesFetched = !1, this.strategiesSettled = !1, I += 1;
420
439
  },
421
440
  /**
422
441
  * Opens a Smart Recommender strategy page in a new tab and refreshes the list every time
@@ -503,6 +522,7 @@ const Q = () => ({
503
522
  this.blockStates[r].legacyConversionLoading = !0;
504
523
  try {
505
524
  const n = await m.migrateLegacyStrategy(t, e);
525
+ this.invalidateStrategies();
506
526
  try {
507
527
  await this.fetchStrategies();
508
528
  } catch (o) {
@@ -606,7 +626,7 @@ const Q = () => ({
606
626
  const n = [...e.recommendationConfigs.filters];
607
627
  n[r] = {
608
628
  ...t,
609
- isValid: K(t)
629
+ isValid: q(t)
610
630
  }, e.recommendationConfigs.filters = n;
611
631
  }
612
632
  },
@@ -670,22 +690,22 @@ const Q = () => ({
670
690
  const t = [
671
691
  this.currentRecommendationId,
672
692
  this.configVersion,
673
- b
693
+ I
674
694
  ].join(":");
675
- if (y && I === t) {
695
+ if (y && b === t) {
676
696
  await y;
677
697
  return;
678
698
  }
679
- I = t, y = this._doFetchProducts();
699
+ b = t, y = this._doFetchProducts();
680
700
  try {
681
701
  await y;
682
702
  } finally {
683
- I === t && (y = null, I = "");
703
+ b === t && (y = null, b = "");
684
704
  }
685
705
  },
686
706
  async _doFetchProducts() {
687
707
  var h;
688
- const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = k();
708
+ const t = this.currentRecommendationId, e = this.blockStates[t], { recommendationConfigs: r } = e, n = R();
689
709
  if (r.strategyId && n.isFeatureEnabled("reusableRecommendationStrategy")) {
690
710
  await this._doFetchStrategyProducts(t);
691
711
  return;
@@ -705,7 +725,7 @@ const Q = () => ({
705
725
  details: !0,
706
726
  campaignId: n.variationId
707
727
  };
708
- r.strategy === "manualMerchandising" ? c.productId = q(r.productIds) : r.strategy === "similarViewed" && (c.productId = "{itemId}"), r.strategy === "userBased" && (c.userId = "{user_id}"), a && (c.filter = a), r.shuffleProducts && (c.shuffle = !0), Object.assign(
728
+ r.strategy === "manualMerchandising" ? c.productId = K(r.productIds) : r.strategy === "similarViewed" && (c.productId = "{itemId}"), r.strategy === "userBased" && (c.userId = "{user_id}"), a && (c.filter = a), r.shuffleProducts && (c.shuffle = !0), Object.assign(
709
729
  c,
710
730
  $(n.partnerName, r.strategy)
711
731
  );
@@ -0,0 +1,26 @@
1
+ import { ATTR_CUSTOM_PREFIX as f, RECOMMENDATION_ID_ATTR as o } from "../constants/selectors.js";
2
+ const s = new RegExp(`\\s${o}="(\\d+)"`, "g");
3
+ function u(t) {
4
+ if (typeof t == "string")
5
+ return t.trim() !== "";
6
+ if (t && typeof t == "object" && "strategyId" in t) {
7
+ const { strategyId: r } = t;
8
+ return (typeof r == "string" || typeof r == "number") && String(r).trim() !== "";
9
+ }
10
+ return !1;
11
+ }
12
+ function a(t) {
13
+ return new Set([...t.matchAll(s)].map((r) => Number(r[1])));
14
+ }
15
+ function g({ config: t, blockId: r, partnerName: e, campaignUrls: n, loadedIds: i }) {
16
+ return e ? t.partnerName ? t.partnerName !== e : !t.strategyId || !n || !i.has(r) ? !1 : !u(n[String(r)]) : !1;
17
+ }
18
+ function p(t) {
19
+ return t.filter((r) => !r.startsWith(f));
20
+ }
21
+ export {
22
+ g as carriesForeignPartnerConfig,
23
+ u as isDefinedCampaignUrl,
24
+ a as loadedRecommendationIds,
25
+ p as withoutCustomAttributes
26
+ };
package/dist/guido.css CHANGED
@@ -1 +1 @@
1
- @charset "UTF-8";.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-73199fa4] .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-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__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-1ca6baf0]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-36867e2e]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-36867e2e]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-36867e2e]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .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-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{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-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-19d8cb42] .vueperslides__bullets,[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}.legacy-strategy-updated-modal[data-v-da2225a1]{position:relative;z-index:145}
1
+ @charset "UTF-8";.gap-16[data-v-5553d071],.gap-16[data-v-0e1b0c54]{gap:16px}[data-v-73199fa4] .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-87033101]{position:relative;display:inline-block}.new-tag[data-v-87033101]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-87033101] .guido__view-option-selection-desktop svg,[data-v-87033101] .guido__view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-87033101] .in-segments-wrapper__button_selected,[data-v-87033101] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-87033101] .in-tooltip-wrapper-v2__icon{cursor:pointer}.editor-toolbar[data-v-173c3a40]{gap:4px}.version-history-item[data-v-ee4b9c3f]{flex-basis:200px}.version-history[data-v-fad98586]{gap:8px}.version-history__toolbar[data-v-fad98586]{gap:4px}.view-options-wrapper[data-v-6ebabfe4]{position:relative;display:inline-block}.new-tag[data-v-6ebabfe4]{position:absolute;top:-8px;right:-16px;z-index:10}[data-v-6ebabfe4] .guido__verion-history-view-option-selection-desktop svg,[data-v-6ebabfe4] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-6ebabfe4] .in-segments-wrapper__button_selected,[data-v-6ebabfe4] .in-segments-wrapper__button_selected:hover{background-color:#dae1fb}[data-v-6ebabfe4] .in-tooltip-wrapper-v2__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-c61cc8ea]{gap:4px}.header-wrapper[data-v-d11dd577]{min-width:1000px}.guido-loading__wrapper[data-v-07c4b2d8]{height:100%;top:75px!important;bottom:0!important}.guido-editor__wrapper[data-v-36867e2e]{--ribbon-offset: 0px;position:relative;width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__container[data-v-36867e2e]{width:100%;height:calc(100vh - 128px - var(--ribbon-offset))}.guido-editor__no-header[data-v-36867e2e]{height:calc(100vh - 75px - var(--ribbon-offset))}[data-v-293f1c47] .in-breadcrumb-wrapper__links{cursor:pointer}.templates-wrapper[data-v-91a26acd]{gap:16px;grid-template-columns:repeat(3,1fr)}.templates-wrapper .template-wrapper[data-v-91a26acd]{cursor:pointer}.templates-wrapper .template-wrapper .template-container[data-v-91a26acd]{height:274px;padding:2px;transition:none}.templates-wrapper .template-wrapper .template-container.selected[data-v-91a26acd]{padding:1px}.templates-wrapper .template-wrapper .template-container .thumbnail[data-v-91a26acd]{object-fit:cover;transform:scale(1)}[data-v-b9a93c6e] .guido__verion-history-view-option-selection-desktop svg,[data-v-b9a93c6e] .guido__verion-history-view-option-selection-mobile svg{margin:0 0 0 2px}[data-v-b9a93c6e] .in-segments-wrapper__button_selected,[data-v-b9a93c6e] .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-cf946232]{min-width:602px;height:70vh;min-height:583px;border-radius:10px}.desktop-preview iframe[data-v-cf946232]{min-height:504px}.iframe-wrapper[data-v-f255b2bb]{width:258px}.iframe-scaled[data-v-f255b2bb]{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-6bcaca8a] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-f16f20f8] .vueperslides__bullets{pointer-events:none!important}[data-v-f16f20f8] .vueperslides__parallax-wrapper{padding-bottom:110px!important}[data-v-bb3cca55] .vueperslides__bullets{pointer-events:none!important}[data-v-bb3cca55] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-19d8cb42] .vueperslides__bullets,[data-v-ec2027ff] .vueperslides__bullets,[data-v-b09e80c4] .vueperslides__bullets{pointer-events:none!important}[data-v-b09e80c4] .vueperslides__parallax-wrapper{height:110px!important;padding-bottom:110px!important}[data-v-9bdef600] .vueperslides__parallax-wrapper{padding-bottom:110px!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd]{width:100%;max-width:none}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-skeleton{width:100%!important}.assign-strategy-drawer-content .assign-strategy-select[data-v-6ce48dfd] .in-dropdown-box__container{width:413px}.assign-strategy-drawer .spaced-dot-sep{background-image:linear-gradient(90deg,#91949f 20%,#fff0 0);background-position:center bottom;background-repeat:repeat-x;background-size:5px 1px}.assign-strategy-drawer .spaced-dot-sep--top{background-position:center top}.assign-strategy-drawer .spaced-dot-sep--fc-n:first-child{background:none}.legacy-strategy-updated-modal[data-v-da2225a1]{position:relative;z-index:145}
@@ -278,6 +278,14 @@ export declare const TemplateSchema: v.ObjectSchema<{
278
278
  * mount. Non-numbers still fail, like every other field in this schema.
279
279
  */
280
280
  readonly trackIdCounter: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.TransformAction<number, number>]>, 0>;
281
+ /**
282
+ * The variation's saved `recommendationCampaignUrls`, keyed by block id. A block
283
+ * that still names a strategy but has no entry here had it dropped by a
284
+ * cross-account duplicate, so Guido resets it on load (SD-151945). Omit it and
285
+ * that check is off, and so is any non-object value such as `null`, because a reset
286
+ * cannot be undone. Hosts send `[]` for an empty map.
287
+ */
288
+ readonly recommendationCampaignUrls: v.OptionalSchema<v.SchemaWithPipe<readonly [v.UnknownSchema, v.TransformAction<unknown, Record<string, unknown> | undefined>]>, undefined>;
281
289
  /** Migration-only inputs (legacy block configs) */
282
290
  readonly migration: v.OptionalSchema<v.ObjectSchema<{
283
291
  /**
@@ -701,6 +709,14 @@ export declare const GuidoConfigSchema: v.ObjectSchema<{
701
709
  * mount. Non-numbers still fail, like every other field in this schema.
702
710
  */
703
711
  readonly trackIdCounter: v.OptionalSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.TransformAction<number, number>]>, 0>;
712
+ /**
713
+ * The variation's saved `recommendationCampaignUrls`, keyed by block id. A block
714
+ * that still names a strategy but has no entry here had it dropped by a
715
+ * cross-account duplicate, so Guido resets it on load (SD-151945). Omit it and
716
+ * that check is off, and so is any non-object value such as `null`, because a reset
717
+ * cannot be undone. Hosts send `[]` for an empty map.
718
+ */
719
+ readonly recommendationCampaignUrls: v.OptionalSchema<v.SchemaWithPipe<readonly [v.UnknownSchema, v.TransformAction<unknown, Record<string, unknown> | undefined>]>, undefined>;
704
720
  /** Migration-only inputs (legacy block configs) */
705
721
  readonly migration: v.OptionalSchema<v.ObjectSchema<{
706
722
  /**
@@ -43,6 +43,7 @@ export declare const useConfig: () => {
43
43
  selectedUnsubscribePages: number[];
44
44
  forceRecreate: boolean;
45
45
  trackIdCounter: number;
46
+ recommendationCampaignUrls?: Record<string, unknown> | undefined;
46
47
  migration: {
47
48
  recommendationConfigs: {
48
49
  [x: string]: {
@@ -180,6 +181,7 @@ export declare const useConfig: () => {
180
181
  selectedUnsubscribePages: number[];
181
182
  forceRecreate: boolean;
182
183
  trackIdCounter: number;
184
+ recommendationCampaignUrls?: Record<string, unknown> | undefined;
183
185
  migration: {
184
186
  recommendationConfigs: {
185
187
  [x: string]: {
@@ -137,6 +137,12 @@ export declare class RecommendationBlock extends Block {
137
137
  * heals templates saved before this feature without dirtying current ones.
138
138
  */
139
139
  private _healHidePriceAttr;
140
+ /**
141
+ * Empties a block copied in from another account: its strategy and attribute types
142
+ * are account-scoped and would not resolve here (SD-151945). Layout, locale and
143
+ * currency stay. The write stamps the current account, so the next pass is a no-op.
144
+ */
145
+ private _resetForeignPartnerConfig;
140
146
  /**
141
147
  * Gets the recommendation-id from a block node
142
148
  */
@@ -543,6 +543,11 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
543
543
  openRemoveStrategyModal(): void;
544
544
  closeRemoveStrategyModal(): void;
545
545
  fetchStrategies(): Promise<void>;
546
+ /**
547
+ * Drops what the store still holds for a block whose account-scoped config was just
548
+ * reset in the document (SD-151945), so the panel re-seeds from the emptied node.
549
+ */
550
+ resetPartnerScopedConfig(id: number): void;
546
551
  /**
547
552
  * Clears what a block inherited from the id it arrived holding, so the panel fetches for it.
548
553
  * A re-dropped saved module can keep the source's id — and its "already fetched" entry —
@@ -83,6 +83,12 @@ export interface RecommendationNodeConfig {
83
83
  */
84
84
  filters: Filter[];
85
85
  strategyId: string;
86
+ /**
87
+ * Account (`config.partner.name`) that last wrote the strategy config. Strategy ids and
88
+ * attribute types are account-scoped, so a block opened under another account is reset.
89
+ * Absent on blocks saved before SD-151945.
90
+ */
91
+ partnerName?: string;
86
92
  /**
87
93
  * Layout orientation
88
94
  * - 'grid': Products in a grid, attributes aligned across products
@@ -0,0 +1,27 @@
1
+ import type { RecommendationNodeConfig } from '../types/nodeConfig';
2
+ /**
3
+ * Mirrors the backend's `RecommendationCampaignUrls::isDefined`: a legacy feed URL
4
+ * string or an entry that names a strategy.
5
+ */
6
+ export declare function isDefinedCampaignUrl(value: unknown): boolean;
7
+ /** Recommendation block ids present in the HTML the host loaded the editor with. */
8
+ export declare function loadedRecommendationIds(html: string): Set<number>;
9
+ export interface PartnerScopeInputs {
10
+ config: Pick<RecommendationNodeConfig, 'strategyId' | 'partnerName'>;
11
+ blockId: number;
12
+ partnerName: string;
13
+ /** `undefined` when the host does not pass the map — the unstamped check is then off. */
14
+ campaignUrls: Record<string, unknown> | undefined;
15
+ loadedIds: Set<number>;
16
+ }
17
+ /**
18
+ * Whether a block carries another account's strategy config (SD-151945).
19
+ *
20
+ * A stamped block is judged by its stamp. An unstamped one predates the stamp, so it
21
+ * falls back to the backend's own signal: a cross-account duplicate drops the block's
22
+ * strategy entry from the campaign URL map but leaves the HTML untouched. That check
23
+ * only holds for blocks the host loaded, whose map entry the host actually sent — a
24
+ * saved module or a clone arrives under an id the map never had.
25
+ */
26
+ export declare function carriesForeignPartnerConfig({ config, blockId, partnerName, campaignUrls, loadedIds }: PartnerScopeInputs): boolean;
27
+ export declare function withoutCustomAttributes(composition: string[]): string[];