@useinsider/guido 3.17.0-beta.db80c84 → 3.17.0-beta.e6704da

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 (70) hide show
  1. package/README.md +1 -0
  2. package/dist/@types/config/schemas.js +12 -6
  3. package/dist/components/Guido.vue.js +6 -6
  4. package/dist/components/Guido.vue2.js +63 -61
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +18 -0
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +70 -0
  7. package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue.js +20 -0
  8. package/dist/components/organisms/extensions/recommendation/StrategyInfoBox.vue2.js +55 -0
  9. package/dist/composables/useCustomInterfaceAppearance.js +19 -16
  10. package/dist/composables/useRecommendation.js +41 -34
  11. package/dist/composables/useStripo.js +14 -14
  12. package/dist/config/migrator/index.js +8 -9
  13. package/dist/config/migrator/recommendation/compositionMapper.js +20 -20
  14. package/dist/config/migrator/recommendation/extractors.js +24 -29
  15. package/dist/config/migrator/recommendation/htmlBuilder.js +130 -116
  16. package/dist/config/migrator/recommendationMigrator.js +15 -16
  17. package/dist/enums/academy.js +2 -1
  18. package/dist/enums/date.js +4 -3
  19. package/dist/enums/extensions/recommendationBlock.js +25 -23
  20. package/dist/extensions/Blocks/Recommendation/constants/blockIds.js +1 -1
  21. package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
  22. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +21 -20
  23. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +28 -34
  24. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +256 -323
  25. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +158 -157
  26. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +141 -0
  27. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +0 -1
  28. package/dist/extensions/Blocks/Recommendation/extension.js +29 -31
  29. package/dist/extensions/Blocks/Recommendation/settingsPanel.js +4 -23
  30. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +216 -68
  31. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +3 -3
  32. package/dist/extensions/Blocks/Recommendation/templates/utils.js +107 -85
  33. package/dist/extensions/Blocks/common-control.js +22 -19
  34. package/dist/guido.css +1 -1
  35. package/dist/services/recommendationApi.js +78 -29
  36. package/dist/src/@types/config/schemas.d.ts +12 -0
  37. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +3 -0
  38. package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBox.vue.d.ts +24 -0
  39. package/dist/src/composables/useConfig.d.ts +2 -0
  40. package/dist/src/composables/useRecommendation.d.ts +1 -0
  41. package/dist/src/config/migrator/recommendation/extractors.d.ts +0 -8
  42. package/dist/src/enums/academy.d.ts +1 -0
  43. package/dist/src/enums/extensions/recommendationBlock.d.ts +2 -0
  44. package/dist/src/extensions/Blocks/Recommendation/constants/blockIds.d.ts +1 -2
  45. package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +0 -7
  46. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +0 -1
  47. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +1 -1
  48. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +0 -10
  49. package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +0 -10
  50. package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +0 -1
  51. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +14 -3
  52. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +29 -0
  53. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +0 -1
  54. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +214 -10
  55. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +6 -0
  56. package/dist/src/extensions/Blocks/common-control.d.ts +4 -1
  57. package/dist/src/mock/api/recommendation-strategies.d.ts +43 -0
  58. package/dist/src/services/recommendationApi.d.ts +4 -1
  59. package/dist/src/stores/config.d.ts +18 -0
  60. package/dist/static/styles/components/recommendation-strategy.css.js +171 -0
  61. package/dist/static/styles/customEditorStyle.css.js +1 -3
  62. package/dist/utils/dateUtil.js +23 -10
  63. package/dist/utils/templatePreparation.js +37 -34
  64. package/package.json +2 -1
  65. package/dist/config/migrator/recommendationTitleMigrator.js +0 -119
  66. package/dist/extensions/Blocks/Recommendation/controls/title/index.js +0 -44
  67. package/dist/extensions/Blocks/Recommendation/templates/titleRows.js +0 -33
  68. package/dist/src/config/migrator/recommendationTitleMigrator.d.ts +0 -5
  69. package/dist/src/extensions/Blocks/Recommendation/controls/title/index.d.ts +0 -86
  70. package/dist/src/extensions/Blocks/Recommendation/templates/titleRows.d.ts +0 -13
@@ -99,6 +99,7 @@ export declare const useConfig: () => {
99
99
  autosave: boolean;
100
100
  allowlistEnabled: boolean;
101
101
  linkTrackingIds: boolean;
102
+ reusableRecommendationStrategy: boolean;
102
103
  };
103
104
  blocks: {
104
105
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -233,6 +234,7 @@ export declare const useConfig: () => {
233
234
  autosave: boolean;
234
235
  allowlistEnabled: boolean;
235
236
  linkTrackingIds: boolean;
237
+ reusableRecommendationStrategy: boolean;
236
238
  } | null>;
237
239
  blocks: import("vue").ComputedRef<{
238
240
  excludeDefaults: ("amp-accordion" | "amp-carousel" | "amp-form-controls" | "banner-block" | "button-block" | "html-block" | "image-block" | "menu-block" | "social-block" | "spacer-block" | "text-block" | "timer-block" | "video-block")[];
@@ -18,6 +18,7 @@ export declare const useRecommendation: () => {
18
18
  getRecommendationCampaignData: (id: string) => CampaignData;
19
19
  buildCampaignUrl: (campaignId: string, overrides?: {
20
20
  strategy: string;
21
+ strategyId: string;
21
22
  language: string;
22
23
  currencyCode: string;
23
24
  size: string;
@@ -1,12 +1,4 @@
1
1
  export declare function extractTitleText(block: Element): string;
2
- /**
3
- * Fallback for legacy configs that carry no `p_recommendation_title` variable:
4
- * the rendered HTML decides. A missing or `display: none` title container means
5
- * the user never saw a title, so the migrated block keeps it toggled off.
6
- * @param block - The legacy recommendation block element
7
- * @returns True when the legacy block renders a visible title
8
- */
9
- export declare function hasVisibleTitle(block: Element): boolean;
10
2
  /**
11
3
  * Card background lives on either the block (`bgcolor`/`style`) or per-card
12
4
  * cells (`.product-card`). Returns empty string when no background is set —
@@ -8,5 +8,6 @@ export declare const ACADEMY_LINKS: {
8
8
  readonly EMAIL_EDITOR: "https://academy.insiderone.com/docs/email-drag-and-drop-editor";
9
9
  readonly GLOBAL_UNSUBSCRIBE: "https://academy.insiderone.com/docs/global-unsubscribe-preference-center";
10
10
  readonly AMP_FOR_EMAILS: "https://academy.insiderone.com/docs/amp-for-emails";
11
+ readonly EMAIL_RECOMMENDATION_BLOCK: "https://academy.insiderone.com/docs/new-editor-email-recommendation-block";
11
12
  };
12
13
  export type AcademyLinkKey = keyof typeof ACADEMY_LINKS;
@@ -3,7 +3,9 @@ import type { RecommendationFeedItem } from '@@/Types/recommendation';
3
3
  export declare const URLS: {
4
4
  RECOMMENDATION_API_URL: string;
5
5
  PRODUCT_ATTRIBUTES_PATH: string;
6
+ RECOMMENDATION_STRATEGIES_PATH: string;
6
7
  };
8
+ export declare const RRS_ACTIVE_EMAIL_FILTER = "[sr_strategies.status][=][active]*[sr_strategies.suitable_channels][~][EMAIL]";
7
9
  export declare const QUERY_PARAMS: {
8
10
  CLIENT_ID: string;
9
11
  };
@@ -10,6 +10,5 @@ export declare enum RecommendationBlockId {
10
10
  OMNIBUS_PRICE = "recommendation-block-omnibus-price",
11
11
  OMNIBUS_DISCOUNT = "recommendation-block-omnibus-discount",
12
12
  IMAGE = "recommendation-block-image",
13
- CUSTOM_ATTRIBUTE = "recommendation-block-custom-attribute",
14
- TITLE = "recommendation-block-title"
13
+ CUSTOM_ATTRIBUTE = "recommendation-block-custom-attribute"
15
14
  }
@@ -65,12 +65,5 @@ export declare enum RecommendationControlId {
65
65
  CUSTOM_ATTR_SIZE = "recommendation-block-custom-attr-size-control",
66
66
  CUSTOM_ATTR_STYLE = "recommendation-block-custom-attr-style-control",
67
67
  CUSTOM_ATTR_TEXT_TRIM = "recommendation-block-custom-attr-text-trim-control",
68
- TITLE_ALIGN = "recommendation-block-title-align-control",
69
- TITLE_BACKGROUND = "recommendation-block-title-background-control",
70
- TITLE_COLOR = "recommendation-block-title-color-control",
71
- TITLE_FONT_FAMILY = "recommendation-block-title-font-family-control",
72
- TITLE_PADDINGS = "recommendation-block-title-paddings-control",
73
- TITLE_SIZE = "recommendation-block-title-size-control",
74
- TITLE_STYLE = "recommendation-block-title-style-control",
75
68
  SYNC_INFO_MESSAGE = "recommendation-block-sync-info-message"
76
69
  }
@@ -32,7 +32,6 @@ export declare const DEFAULT_COMPOSITION: string[];
32
32
  /**
33
33
  * Default visibility settings for card elements
34
34
  * Omnibus elements are hidden by default (not all regions require them)
35
- * The block-level title is visible on a fresh drop.
36
35
  */
37
36
  export declare const DEFAULT_VISIBILITY: Record<string, boolean>;
38
37
  /**
@@ -8,6 +8,6 @@
8
8
  */
9
9
  export { RecommendationBlockId } from './blockIds';
10
10
  export { RecommendationControlId } from './controlIds';
11
- export { BLOCK_ROOT_SELECTOR, CONTAINER_SELECTOR, DESKTOP_CONTAINER_SELECTOR, MOBILE_CONTAINER_SELECTOR, MOBILE_ROW_SELECTOR, CSS_CLASS_RECO_BUTTON, CSS_CLASS_SKIP_COMPILE, RECOMMENDATION_VARIABLE_BUILTIN_ATTRIBUTES, CURRENCY_ATTR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, ATTR_RECOMMENDATION_TITLE, SELECTOR_TITLE_CELL, ATTR_CUSTOM_PREFIX, ATTR_DATA_CARD_COMPOSITION, ATTR_DATA_CUSTOM_ATTRIBUTES, ATTR_PRODUCT_ATTR, CSS_CLASS_ATTRIBUTE_ROW, CSS_CLASS_SPACER, SELECTOR_ATTRIBUTE_ROW, ATTR_DATA_ATTRIBUTE_TYPE, ATTR_DATA_VISIBILITY, PRODUCT_ATTRIBUTE_PREFIX, BUILT_IN_DEFAULT_ATTRIBUTES, } from './selectors';
11
+ export { BLOCK_ROOT_SELECTOR, CONTAINER_SELECTOR, DESKTOP_CONTAINER_SELECTOR, MOBILE_CONTAINER_SELECTOR, MOBILE_ROW_SELECTOR, CSS_CLASS_RECO_BUTTON, CSS_CLASS_SKIP_COMPILE, RECOMMENDATION_VARIABLE_BUILTIN_ATTRIBUTES, CURRENCY_ATTR, ATTR_PRODUCT_IMAGE, ATTR_PRODUCT_NAME, ATTR_PRODUCT_PRICE, ATTR_PRODUCT_OLD_PRICE, ATTR_PRODUCT_OMNIBUS_PRICE, ATTR_PRODUCT_OMNIBUS_DISCOUNT, ATTR_PRODUCT_BUTTON, ATTR_CUSTOM_PREFIX, ATTR_DATA_CARD_COMPOSITION, ATTR_DATA_CUSTOM_ATTRIBUTES, ATTR_PRODUCT_ATTR, SELECTOR_ATTRIBUTE_ROW, ATTR_DATA_ATTRIBUTE_TYPE, PRODUCT_ATTRIBUTE_PREFIX, BUILT_IN_DEFAULT_ATTRIBUTES, } from './selectors';
12
12
  export { LAYOUT_VALUES, LAYOUT_OPTIONS, DEFAULT_PRODUCTS_PER_ROW, DEFAULT_CARDS_IN_ROW, DEFAULT_MOBILE_CARDS_IN_ROW, MAX_PRODUCT_COUNT, MIN_PRODUCT_COUNT, MAX_PRODUCTS_PER_ROW, MIN_PRODUCTS_PER_ROW, MAX_MOBILE_PRODUCTS_PER_ROW, MIN_MOBILE_PRODUCTS_PER_ROW, DEFAULT_COLUMN_SPACING, DEFAULT_ROW_SPACING, DEFAULT_MOBILE_COLUMN_SPACING, DEFAULT_MOBILE_ROW_SPACING, MIN_SPACING, MAX_SPACING, SPACING_STEP, } from './layout';
13
13
  export { DEFAULT_NODE_CONFIG, DEFAULT_CURRENCY, DEFAULT_COMPOSITION, DEFAULT_VISIBILITY, CURRENT_CONFIG_VERSION, EXCLUDED_ALGORITHM_IDS, } from './defaultConfig';
@@ -58,10 +58,6 @@ export declare const ATTR_PRODUCT_OLD_PRICE = "productOldPrice";
58
58
  export declare const ATTR_PRODUCT_OMNIBUS_PRICE = "productOmnibusPrice";
59
59
  export declare const ATTR_PRODUCT_OMNIBUS_DISCOUNT = "productOmnibusDiscount";
60
60
  export declare const ATTR_PRODUCT_BUTTON = "productButton";
61
- export declare const ATTR_RECOMMENDATION_TITLE = "recommendationTitle";
62
- export declare const CSS_CLASS_TITLE_CELL = "ins-recommendation-title";
63
- /** Title cell — the only `esd-block-text` living outside the product containers. */
64
- export declare const SELECTOR_TITLE_CELL = ".ins-recommendation-title";
65
61
  /**
66
62
  * Custom attribute constants
67
63
  * Used for dynamically added product attributes in Card Composition
@@ -74,16 +70,10 @@ export declare const ATTR_DATA_CUSTOM_ATTRIBUTES = "data-custom-attributes";
74
70
  export declare const ATTR_DATA_CARD_COMPOSITION = "data-card-composition";
75
71
  /** HTML attribute on <td> elements identifying the product attribute for compiler template variable generation */
76
72
  export declare const ATTR_PRODUCT_ATTR = "product-attr";
77
- /** Class every composition attribute row carries — the visibility toggle and the compiler both key on it */
78
- export declare const CSS_CLASS_ATTRIBUTE_ROW = "recommendation-attribute-row";
79
73
  /** Row wrapper of one composition entry inside a product card */
80
74
  export declare const SELECTOR_ATTRIBUTE_ROW = ".recommendation-attribute-row";
81
75
  /** HTML attribute on an attribute row holding its composition key */
82
76
  export declare const ATTR_DATA_ATTRIBUTE_TYPE = "data-attribute-type";
83
- /** HTML attribute on an attribute row holding its visibility (`1` / `0`) */
84
- export declare const ATTR_DATA_VISIBILITY = "data-visibility";
85
- /** Class on the spacer cell of the row that trails a title */
86
- export declare const CSS_CLASS_SPACER = "spacer";
87
77
  /** Prefix `resolveProductAttrValue` puts on custom (non-default) product attributes in `product-attr` values */
88
78
  export declare const PRODUCT_ATTRIBUTE_PREFIX = "product_attribute.";
89
79
  /**
@@ -33,8 +33,6 @@ export declare class RecommendationCardCompositionControl extends CommonControl
33
33
  private _normalizeComposition;
34
34
  private _readCustomAttributesFromNode;
35
35
  private _readVisibilityFromRows;
36
- private _withTitlePresence;
37
- private _hasTitle;
38
36
  private _getDefaultVisibilities;
39
37
  private _extractVisibilityFromRows;
40
38
  private _parseVisibilityValue;
@@ -189,14 +187,6 @@ export declare class RecommendationCardCompositionControl extends CommonControl
189
187
  */
190
188
  private _buildCompositionHtml;
191
189
  private _applyVisibilityToBlock;
192
- private _applyTitleVisibilityToBlock;
193
- private _resolveTitleInjection;
194
- private _findTitleRows;
195
- private _findTitleRowsByClass;
196
- private _isSpacerRow;
197
- private _findTitleContainerBody;
198
- private _readInnerHtml;
199
- private _defaultTitleParagraph;
200
190
  /**
201
191
  * Finds the composition array index for the Nth custom attribute (0-based).
202
192
  * Scans left-to-right, counting only entries with the custom prefix.
@@ -11,7 +11,6 @@
11
11
  */
12
12
  export { RecommendationBlockControl, CONTROL_BLOCK_ID, AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, } from './main';
13
13
  export * from './main/utils';
14
- export { TitleControls } from './title';
15
14
  export { NameControls } from './name';
16
15
  export { PriceControls } from './price';
17
16
  export { OldPriceControls } from './oldPrice';
@@ -9,8 +9,9 @@ import { PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID } from './pricePlacem
9
9
  import { ProductCountControl, PRODUCT_COUNT_CONTROL_ID } from './productCount';
10
10
  import { ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID } from './productLayout';
11
11
  import { ShuffleControl, SHUFFLE_CONTROL_ID } from './shuffle';
12
+ import { StrategyControl, STRATEGY_CONTROL_ID } from './strategy';
12
13
  export declare const CONTROL_BLOCK_ID = "ui-elements-recommendation-block";
13
- export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, };
14
+ export { AlgorithmControl, ALGORITHM_CONTROL_ID, LocaleControl, LOCALE_CONTROL_ID, CurrencyControl, CURRENCY_CONTROL_ID, ProductCountControl, PRODUCT_COUNT_CONTROL_ID, ProductLayoutControl, PRODUCT_LAYOUT_CONTROL_ID, FiltersControl, FILTERS_CONTROL_ID, ShuffleControl, SHUFFLE_CONTROL_ID, LayoutOrientationControl, LAYOUT_ORIENTATION_CONTROL_ID, PricePlacementControl, PRICE_PLACEMENT_CONTROL_ID, StrategyControl, STRATEGY_CONTROL_ID, };
14
15
  export * from './utils';
15
16
  /**
16
17
  * Main recommendation block control that composes all sub-controls
@@ -29,7 +30,10 @@ export declare class RecommendationBlockControl extends CommonControl {
29
30
  private shuffleControl;
30
31
  private pricePlacementControl;
31
32
  private layoutOrientationControl;
33
+ private strategyControl;
32
34
  getId(): string;
35
+ /** Every sub-control the coordinator owns, in panel order. */
36
+ private get _subControls();
33
37
  getTemplate(): string;
34
38
  onRender(): Promise<void>;
35
39
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
@@ -107,8 +111,15 @@ export declare class RecommendationBlockControl extends CommonControl {
107
111
  */
108
112
  private _listenStateUpdates;
109
113
  /**
110
- * Persists the current filter state from Pinia store to the Stripo node config.
111
- * This ensures filters survive template save/reload cycles.
114
+ * Persists the current filter + strategy state from Pinia store to the
115
+ * Stripo node config. This ensures they survive template save/reload cycles
116
+ * (strategyId must be in esd-ext-config before any save — SD-149105).
117
+ *
118
+ * `size` rides along because assigning a strategy overwrites it in the
119
+ * store only. Without this write, `_syncNodeConfigToStore` re-seeds the
120
+ * store from the stale node config on the next panel open, and a block
121
+ * whose saved HTML has the strategy's slot count gets rebuilt against the
122
+ * old one — resetting migrator-applied per-element styles.
112
123
  */
113
124
  private _persistFiltersToNodeConfig;
114
125
  }
@@ -0,0 +1,29 @@
1
+ import { CommonControl } from '../../../common-control';
2
+ export declare const STRATEGY_CONTROL_ID = "recommendation-strategy-control";
3
+ export declare class StrategyControl extends CommonControl {
4
+ private store;
5
+ private storeUnsubscription;
6
+ private listeners;
7
+ getId(): string;
8
+ getTemplate(): string;
9
+ /**
10
+ * Change / Remove are icon+text actions in the design, not buttons — and
11
+ * `ue-button` cannot pair a caption with an arbitrary icon, so these are
12
+ * plain elements. Click wiring is by id, which works on any element.
13
+ *
14
+ * The icon is a CSS mask, not inline SVG: Stripo re-creates the control's
15
+ * markup through Angular, which rebuilds `<svg>` outside the SVG namespace
16
+ * (the view-box attribute comes back lowercased) and it never paints.
17
+ */
18
+ private _strategyAction;
19
+ onRender(): void;
20
+ onDestroy(): void;
21
+ private _teardown;
22
+ private _setupButtonListeners;
23
+ /**
24
+ * Toggles empty vs assigned state from the store's current block config.
25
+ * Display name comes from the listing; falls back to the raw id while the
26
+ * listing loads (or when the strategy is no longer listed).
27
+ */
28
+ private _renderState;
29
+ }
@@ -70,7 +70,6 @@ export interface RegenerateProductRowsOptions {
70
70
  /** Optional: pass composition directly to avoid stale DOM reads after setAttribute */
71
71
  composition?: string[];
72
72
  }
73
- export declare function getMainContainerTbody(currentNode: ImmutableHtmlNode): ImmutableHtmlNode | null;
74
73
  /**
75
74
  * Regenerates only the mobile product container rows and commits in a single apply().
76
75
  * Standalone entry point for callers that change mobile-only settings
@@ -1,4 +1,4 @@
1
- import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationProduct } from '@@/Types/recommendation';
1
+ import type { Orientation, Languages, Currency, NumericSeparator, FiltersResponse, Filter, RecommendationCampaignUrlValue, RecommendationProduct, RrsStrategy } from '@@/Types/recommendation';
2
2
  export interface PerBlockConfigs {
3
3
  cardsInRow: number;
4
4
  currencySettings: {
@@ -21,6 +21,8 @@ export interface PerBlockConfigs {
21
21
  sendProductRequestFlag: boolean;
22
22
  shuffleProducts: boolean;
23
23
  strategy: string;
24
+ /** Assigned RRS id ('' = none) — mirrors RecommendationNodeConfig.strategyId (SD-149105) */
25
+ strategyId: string;
24
26
  textTrimming: boolean;
25
27
  unresponsive: boolean;
26
28
  size: string;
@@ -33,6 +35,8 @@ interface PerBlockState {
33
35
  recommendationProducts: RecommendationProduct[];
34
36
  filterStatus: boolean;
35
37
  filterSelectionDrawerStatus: boolean;
38
+ /** Assign Recommendation Strategy drawer visibility (SD-149105) */
39
+ assignStrategyDrawerStatus: boolean;
36
40
  filterGroup: number;
37
41
  /** Whether initial API data (filters, algorithms, products) has been fetched for this block */
38
42
  isInitialized: boolean;
@@ -47,6 +51,7 @@ interface PerBlockState {
47
51
  */
48
52
  export interface PerBlockUrlConfig {
49
53
  strategy: string;
54
+ strategyId: string;
50
55
  language: string;
51
56
  size: string;
52
57
  productIds: string[];
@@ -59,11 +64,14 @@ export interface PerBlockUrlConfig {
59
64
  currencyThousandSeparator: string;
60
65
  }
61
66
  interface StoreState {
62
- recommendationCampaignUrls: Record<string, string>;
67
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
63
68
  activePredictiveAlgorithms: number[];
64
69
  languages: Languages;
65
70
  currencyList: Currency[];
66
71
  filterList: FiltersResponse;
72
+ strategies: RrsStrategy[];
73
+ strategiesLoading: boolean;
74
+ strategyUrlTemplates: Record<string, string>;
67
75
  blockStates: Record<number, PerBlockState>;
68
76
  currentRecommendationId: number | null;
69
77
  configVersion: number;
@@ -74,7 +82,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
74
82
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
75
83
  */
76
84
  recommendationConfigs(state: {
77
- recommendationCampaignUrls: Record<string, string>;
85
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
78
86
  activePredictiveAlgorithms: number[];
79
87
  languages: Languages;
80
88
  currencyList: {
@@ -82,6 +90,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
82
90
  value: string;
83
91
  }[];
84
92
  filterList: FiltersResponse;
93
+ strategies: {
94
+ [x: string]: unknown;
95
+ strategy_id: number;
96
+ name: string;
97
+ status: string;
98
+ suitable_channels: string;
99
+ size?: (number | string) | undefined;
100
+ }[];
101
+ strategiesLoading: boolean;
102
+ strategyUrlTemplates: Record<string, string>;
85
103
  blockStates: Record<number, PerBlockState>;
86
104
  currentRecommendationId: number | null;
87
105
  configVersion: number;
@@ -90,7 +108,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
90
108
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
91
109
  */
92
110
  recommendationProducts(state: {
93
- recommendationCampaignUrls: Record<string, string>;
111
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
94
112
  activePredictiveAlgorithms: number[];
95
113
  languages: Languages;
96
114
  currencyList: {
@@ -98,6 +116,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
98
116
  value: string;
99
117
  }[];
100
118
  filterList: FiltersResponse;
119
+ strategies: {
120
+ [x: string]: unknown;
121
+ strategy_id: number;
122
+ name: string;
123
+ status: string;
124
+ suitable_channels: string;
125
+ size?: (number | string) | undefined;
126
+ }[];
127
+ strategiesLoading: boolean;
128
+ strategyUrlTemplates: Record<string, string>;
101
129
  blockStates: Record<number, PerBlockState>;
102
130
  currentRecommendationId: number | null;
103
131
  configVersion: number;
@@ -106,7 +134,33 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
106
134
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterSelectionDrawerStatus
107
135
  */
108
136
  filterSelectionDrawerStatus(state: {
109
- recommendationCampaignUrls: Record<string, string>;
137
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
138
+ activePredictiveAlgorithms: number[];
139
+ languages: Languages;
140
+ currencyList: {
141
+ text: string;
142
+ value: string;
143
+ }[];
144
+ filterList: FiltersResponse;
145
+ strategies: {
146
+ [x: string]: unknown;
147
+ strategy_id: number;
148
+ name: string;
149
+ status: string;
150
+ suitable_channels: string;
151
+ size?: (number | string) | undefined;
152
+ }[];
153
+ strategiesLoading: boolean;
154
+ strategyUrlTemplates: Record<string, string>;
155
+ blockStates: Record<number, PerBlockState>;
156
+ currentRecommendationId: number | null;
157
+ configVersion: number;
158
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
159
+ /**
160
+ * Proxy getter: delegates to blockStates[currentRecommendationId].assignStrategyDrawerStatus
161
+ */
162
+ assignStrategyDrawerStatus(state: {
163
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
110
164
  activePredictiveAlgorithms: number[];
111
165
  languages: Languages;
112
166
  currencyList: {
@@ -114,15 +168,52 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
114
168
  value: string;
115
169
  }[];
116
170
  filterList: FiltersResponse;
171
+ strategies: {
172
+ [x: string]: unknown;
173
+ strategy_id: number;
174
+ name: string;
175
+ status: string;
176
+ suitable_channels: string;
177
+ size?: (number | string) | undefined;
178
+ }[];
179
+ strategiesLoading: boolean;
180
+ strategyUrlTemplates: Record<string, string>;
117
181
  blockStates: Record<number, PerBlockState>;
118
182
  currentRecommendationId: number | null;
119
183
  configVersion: number;
120
184
  } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
185
+ /**
186
+ * The current block's assigned strategy record from the listing,
187
+ * or null when nothing is assigned / the strategy is no longer listed.
188
+ */
189
+ assignedStrategy(state: {
190
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
191
+ activePredictiveAlgorithms: number[];
192
+ languages: Languages;
193
+ currencyList: {
194
+ text: string;
195
+ value: string;
196
+ }[];
197
+ filterList: FiltersResponse;
198
+ strategies: {
199
+ [x: string]: unknown;
200
+ strategy_id: number;
201
+ name: string;
202
+ status: string;
203
+ suitable_channels: string;
204
+ size?: (number | string) | undefined;
205
+ }[];
206
+ strategiesLoading: boolean;
207
+ strategyUrlTemplates: Record<string, string>;
208
+ blockStates: Record<number, PerBlockState>;
209
+ currentRecommendationId: number | null;
210
+ configVersion: number;
211
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): RrsStrategy | null;
121
212
  /**
122
213
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterStatus
123
214
  */
124
215
  filterStatus(state: {
125
- recommendationCampaignUrls: Record<string, string>;
216
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
126
217
  activePredictiveAlgorithms: number[];
127
218
  languages: Languages;
128
219
  currencyList: {
@@ -130,6 +221,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
130
221
  value: string;
131
222
  }[];
132
223
  filterList: FiltersResponse;
224
+ strategies: {
225
+ [x: string]: unknown;
226
+ strategy_id: number;
227
+ name: string;
228
+ status: string;
229
+ suitable_channels: string;
230
+ size?: (number | string) | undefined;
231
+ }[];
232
+ strategiesLoading: boolean;
233
+ strategyUrlTemplates: Record<string, string>;
133
234
  blockStates: Record<number, PerBlockState>;
134
235
  currentRecommendationId: number | null;
135
236
  configVersion: number;
@@ -138,7 +239,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
138
239
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterGroup
139
240
  */
140
241
  filterGroup(state: {
141
- recommendationCampaignUrls: Record<string, string>;
242
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
142
243
  activePredictiveAlgorithms: number[];
143
244
  languages: Languages;
144
245
  currencyList: {
@@ -146,6 +247,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
146
247
  value: string;
147
248
  }[];
148
249
  filterList: FiltersResponse;
250
+ strategies: {
251
+ [x: string]: unknown;
252
+ strategy_id: number;
253
+ name: string;
254
+ status: string;
255
+ suitable_channels: string;
256
+ size?: (number | string) | undefined;
257
+ }[];
258
+ strategiesLoading: boolean;
259
+ strategyUrlTemplates: Record<string, string>;
149
260
  blockStates: Record<number, PerBlockState>;
150
261
  currentRecommendationId: number | null;
151
262
  configVersion: number;
@@ -155,7 +266,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
155
266
  getFilterGroupCount(): number;
156
267
  getUniqueFilterGroups(): number[];
157
268
  getActivePredictiveAlgorithms: (state: {
158
- recommendationCampaignUrls: Record<string, string>;
269
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
159
270
  activePredictiveAlgorithms: number[];
160
271
  languages: Languages;
161
272
  currencyList: {
@@ -163,6 +274,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
163
274
  value: string;
164
275
  }[];
165
276
  filterList: FiltersResponse;
277
+ strategies: {
278
+ [x: string]: unknown;
279
+ strategy_id: number;
280
+ name: string;
281
+ status: string;
282
+ suitable_channels: string;
283
+ size?: (number | string) | undefined;
284
+ }[];
285
+ strategiesLoading: boolean;
286
+ strategyUrlTemplates: Record<string, string>;
166
287
  blockStates: Record<number, PerBlockState>;
167
288
  currentRecommendationId: number | null;
168
289
  configVersion: number;
@@ -171,7 +292,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
171
292
  value: string;
172
293
  }[];
173
294
  getLanguages: (state: {
174
- recommendationCampaignUrls: Record<string, string>;
295
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
175
296
  activePredictiveAlgorithms: number[];
176
297
  languages: Languages;
177
298
  currencyList: {
@@ -179,6 +300,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
179
300
  value: string;
180
301
  }[];
181
302
  filterList: FiltersResponse;
303
+ strategies: {
304
+ [x: string]: unknown;
305
+ strategy_id: number;
306
+ name: string;
307
+ status: string;
308
+ suitable_channels: string;
309
+ size?: (number | string) | undefined;
310
+ }[];
311
+ strategiesLoading: boolean;
312
+ strategyUrlTemplates: Record<string, string>;
182
313
  blockStates: Record<number, PerBlockState>;
183
314
  currentRecommendationId: number | null;
184
315
  configVersion: number;
@@ -187,7 +318,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
187
318
  value: string;
188
319
  }[];
189
320
  getCurrencySymbolList: (state: {
190
- recommendationCampaignUrls: Record<string, string>;
321
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
191
322
  activePredictiveAlgorithms: number[];
192
323
  languages: Languages;
193
324
  currencyList: {
@@ -195,6 +326,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
195
326
  value: string;
196
327
  }[];
197
328
  filterList: FiltersResponse;
329
+ strategies: {
330
+ [x: string]: unknown;
331
+ strategy_id: number;
332
+ name: string;
333
+ status: string;
334
+ suitable_channels: string;
335
+ size?: (number | string) | undefined;
336
+ }[];
337
+ strategiesLoading: boolean;
338
+ strategyUrlTemplates: Record<string, string>;
198
339
  blockStates: Record<number, PerBlockState>;
199
340
  currentRecommendationId: number | null;
200
341
  configVersion: number;
@@ -272,6 +413,52 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
272
413
  * to the snapshot taken when the drawer was opened.
273
414
  */
274
415
  cancelFilterDrawer(): void;
416
+ /**
417
+ * Opens the Assign Strategy drawer for the current block.
418
+ * Selection state lives in the drawer component until Assign is
419
+ * pressed, so closing without assigning needs no snapshot/revert.
420
+ */
421
+ openAssignStrategyDrawer(): void;
422
+ closeAssignStrategyDrawer(): void;
423
+ /**
424
+ * Fetches the active + EMAIL strategy listing. Always fetches fresh
425
+ * (dead-strategy detection and post-create refresh need freshness);
426
+ * only concurrent in-flight calls share one request.
427
+ */
428
+ fetchStrategies(): Promise<void>;
429
+ /**
430
+ * Resolves a strategy's recommendation endpoint template via
431
+ * endpoint-generate, cached per strategy id + revision. Failures throw
432
+ * and are NOT cached, so the next attempt retries.
433
+ *
434
+ * The revision is part of the key because `full_path` bakes in the
435
+ * algorithm path and `size=` as they were when it was generated, while
436
+ * the listing is deliberately never cached — editing a strategy in the
437
+ * panel and re-assigning it here would otherwise call a stale endpoint.
438
+ *
439
+ * A record with no revision is not cached at all: a `<id>:` key can
440
+ * never change, so it would serve the stale template forever — exactly
441
+ * what the revision is here to prevent.
442
+ */
443
+ resolveStrategyUrlTemplate(strategy: RrsStrategy): Promise<string>;
444
+ /**
445
+ * Assigns a strategy to the current block. The config write is
446
+ * synchronous (before any await) so a block switch cannot misdirect
447
+ * it; the configVersion bump persists it to node config and triggers
448
+ * the product refetch via the coordinator control's subscription.
449
+ */
450
+ assignStrategy(strategy: RrsStrategy): void;
451
+ /**
452
+ * Clears the current block's strategy; it falls back to the per-block
453
+ * algorithm settings.
454
+ *
455
+ * `size` goes back to the default rather than staying on the removed
456
+ * strategy's count: the Number of Products control is hidden in RRS
457
+ * mode (D2), so a block left on the strategy's count would have no UI
458
+ * to correct it. The pre-assign count is not restored — that would
459
+ * need a persisted snapshot field; tracked for a later phase.
460
+ */
461
+ removeStrategy(): void;
275
462
  fetchRecommendationCreateData(): Promise<void>;
276
463
  fetchRecommendationFilters(): Promise<void>;
277
464
  addFilterGroup(filterGroup: number): void;
@@ -288,5 +475,22 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
288
475
  hasInvalidBlock(): boolean;
289
476
  fetchRecommendationProducts(): Promise<void>;
290
477
  _doFetchProducts(): Promise<void>;
478
+ /**
479
+ * Fetches products for a strategy-backed block: listing lookup →
480
+ * endpoint-generate template → fill {locale}/{currency}, drop
481
+ * {user_id} (resolved at send time) → fetch. Any failure (dead
482
+ * strategy, resolution error) falls back to placeholder products.
483
+ */
484
+ _doFetchStrategyProducts(blockId: number): Promise<void>;
485
+ /**
486
+ * Writes products to a block's state, padded/clipped to `size` so
487
+ * in-place content updates (which compare DOM element count vs
488
+ * products.length) succeed:
489
+ * - API returned nothing → fill entirely with defaults
490
+ * - fewer than requested → pad with dummies
491
+ * - more than requested → clip, preventing the renderer from extending
492
+ * its slot grid (which would reset migrator-applied styles).
493
+ */
494
+ _setBlockProducts(blockId: number, products: RecommendationProduct[], size: number): void;
291
495
  }>;
292
496
  export {};
@@ -82,6 +82,12 @@ export interface RecommendationNodeConfig {
82
82
  * Uses existing Filter interface from recommendation types
83
83
  */
84
84
  filters: Filter[];
85
+ /**
86
+ * Assigned Reusable Recommendation Strategy id (SD-149105).
87
+ * '' = no strategy assigned; block uses the per-block settings above.
88
+ * When set, algorithm/size/filters/shuffle come from the strategy record.
89
+ */
90
+ strategyId: string;
85
91
  /**
86
92
  * Layout orientation
87
93
  * - 'grid': Products in a grid, attributes aligned across products
@@ -56,6 +56,9 @@ interface ButtonProps {
56
56
  name: string;
57
57
  label: string;
58
58
  id?: string;
59
+ className?: string;
60
+ icon?: string;
61
+ disabled?: boolean;
59
62
  }
60
63
  /**
61
64
  * Common control for all blocks which includes common UI Elements.
@@ -116,7 +119,7 @@ export declare abstract class CommonControl extends Control {
116
119
  icon?: string;
117
120
  }): string;
118
121
  _GuRadioButton({ name, buttons, id }: RadioButtonProps): string;
119
- _GuButton({ name, label, id }: ButtonProps): string;
122
+ _GuButton({ name, label, id, className, icon, disabled }: ButtonProps): string;
120
123
  _GuIcon({ src, className }: IconProps): string;
121
124
  /**
122
125
  *