@useinsider/guido 3.17.0 → 3.18.0-beta.41e529d

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 (120) hide show
  1. package/README.md +6 -5
  2. package/dist/@types/config/schemas.js +10 -7
  3. package/dist/components/Guido.vue.js +10 -10
  4. package/dist/components/Guido.vue2.js +86 -78
  5. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.js +21 -0
  6. package/dist/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue2.js +131 -0
  7. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.js +18 -0
  8. package/dist/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue2.js +25 -0
  9. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.js +17 -0
  10. package/dist/components/organisms/extensions/recommendation/RemoveStrategyModal.vue2.js +57 -0
  11. package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue.js +19 -0
  12. package/dist/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue2.js +63 -0
  13. package/dist/composables/useCustomInterfaceAppearance.js +56 -38
  14. package/dist/composables/useLegacyStrategyConversion.js +52 -0
  15. package/dist/composables/useModuleRepair.js +33 -0
  16. package/dist/composables/useRecommendation.js +41 -34
  17. package/dist/composables/useSave.js +30 -29
  18. package/dist/composables/useStripo.js +15 -15
  19. package/dist/composables/useSyncModuleExtractor.js +15 -13
  20. package/dist/composables/validators/useSyncModuleBlockValidator.js +24 -0
  21. package/dist/config/i18n/en/labels.json.js +1 -1
  22. package/dist/config/migrator/index.js +9 -8
  23. package/dist/config/migrator/recommendation/compositionMapper.js +20 -20
  24. package/dist/config/migrator/recommendation/extractors.js +29 -24
  25. package/dist/config/migrator/recommendation/htmlBuilder.js +116 -130
  26. package/dist/config/migrator/recommendation/settingsMapper.js +17 -17
  27. package/dist/config/migrator/recommendationMigrator.js +31 -25
  28. package/dist/config/migrator/recommendationTitleMigrator.js +119 -0
  29. package/dist/enums/academy.js +2 -1
  30. package/dist/enums/date.js +5 -3
  31. package/dist/enums/extensions/recommendationBlock.js +4 -1
  32. package/dist/extensions/Blocks/Items/block.js +118 -49
  33. package/dist/extensions/Blocks/Items/constants/currency.js +25 -0
  34. package/dist/extensions/Blocks/Items/controls/price/currencyLocation.js +25 -24
  35. package/dist/extensions/Blocks/Items/controls/price/currencySymbol.js +12 -11
  36. package/dist/extensions/Blocks/Items/template.js +153 -152
  37. package/dist/extensions/Blocks/Items/utils/constants.js +4 -0
  38. package/dist/extensions/Blocks/Recommendation/block.js +35 -29
  39. package/dist/extensions/Blocks/Recommendation/constants/blockIds.js +1 -1
  40. package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
  41. package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +29 -27
  42. package/dist/extensions/Blocks/Recommendation/constants/selectors.js +35 -28
  43. package/dist/extensions/Blocks/Recommendation/controls/cardComposition/index.js +309 -236
  44. package/dist/extensions/Blocks/Recommendation/controls/main/index.js +242 -180
  45. package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +159 -0
  46. package/dist/extensions/Blocks/Recommendation/controls/main/utils.js +1 -0
  47. package/dist/extensions/Blocks/Recommendation/controls/title/index.js +44 -0
  48. package/dist/extensions/Blocks/Recommendation/extension.js +31 -29
  49. package/dist/extensions/Blocks/Recommendation/services/configService.js +54 -36
  50. package/dist/extensions/Blocks/Recommendation/settingsPanel.js +23 -4
  51. package/dist/extensions/Blocks/Recommendation/store/recommendation.js +217 -80
  52. package/dist/extensions/Blocks/Recommendation/templates/grid/template.js +3 -3
  53. package/dist/extensions/Blocks/Recommendation/templates/titleRows.js +33 -0
  54. package/dist/extensions/Blocks/Recommendation/templates/utils.js +85 -107
  55. package/dist/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.js +58 -0
  56. package/dist/extensions/Blocks/Recommendation/utils/nodeConfigWriter.js +22 -0
  57. package/dist/extensions/Blocks/Recommendation/utils/recommendationBlockCount.js +10 -6
  58. package/dist/extensions/Blocks/common-control.js +22 -19
  59. package/dist/guido.css +1 -1
  60. package/dist/services/recommendationApi.js +81 -33
  61. package/dist/src/@types/config/schemas.d.ts +6 -0
  62. package/dist/src/components/organisms/extensions/recommendation/AssignStrategyDrawer.vue.d.ts +3 -0
  63. package/dist/src/components/organisms/extensions/recommendation/LegacyStrategyUpdatedModal.vue.d.ts +2 -0
  64. package/dist/src/components/organisms/extensions/recommendation/RemoveStrategyModal.vue.d.ts +2 -0
  65. package/dist/src/components/organisms/extensions/recommendation/StrategyInfoBoxContent.vue.d.ts +15 -0
  66. package/dist/src/composables/useConfig.d.ts +4 -0
  67. package/dist/src/composables/useLegacyStrategyConversion.d.ts +3 -0
  68. package/dist/src/composables/useModuleRepair.d.ts +18 -0
  69. package/dist/src/composables/useRecommendation.d.ts +1 -0
  70. package/dist/src/composables/useSyncModuleExtractor.d.ts +2 -0
  71. package/dist/src/composables/validators/useSyncModuleBlockValidator.d.ts +3 -0
  72. package/dist/src/config/migrator/recommendation/extractors.d.ts +8 -0
  73. package/dist/src/config/migrator/recommendationTitleMigrator.d.ts +5 -0
  74. package/dist/src/enums/academy.d.ts +1 -0
  75. package/dist/src/enums/date.d.ts +1 -0
  76. package/dist/src/enums/extensions/recommendationBlock.d.ts +3 -0
  77. package/dist/src/extensions/Blocks/Items/block.d.ts +35 -0
  78. package/dist/src/extensions/Blocks/Items/constants/currency.d.ts +43 -0
  79. package/dist/src/extensions/Blocks/Items/utils/constants.d.ts +6 -0
  80. package/dist/src/extensions/Blocks/Recommendation/constants/blockIds.d.ts +2 -1
  81. package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +7 -0
  82. package/dist/src/extensions/Blocks/Recommendation/constants/defaultConfig.d.ts +3 -6
  83. package/dist/src/extensions/Blocks/Recommendation/constants/index.d.ts +2 -2
  84. package/dist/src/extensions/Blocks/Recommendation/constants/selectors.d.ts +12 -0
  85. package/dist/src/extensions/Blocks/Recommendation/controls/cardComposition/index.d.ts +11 -0
  86. package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -0
  87. package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +44 -8
  88. package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +17 -0
  89. package/dist/src/extensions/Blocks/Recommendation/controls/main/utils.d.ts +1 -0
  90. package/dist/src/extensions/Blocks/Recommendation/controls/title/index.d.ts +86 -0
  91. package/dist/src/extensions/Blocks/Recommendation/services/configService.d.ts +12 -1
  92. package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +229 -10
  93. package/dist/src/extensions/Blocks/Recommendation/templates/titleRows.d.ts +13 -0
  94. package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +7 -0
  95. package/dist/src/extensions/Blocks/Recommendation/utils/legacyStrategyMigration.d.ts +39 -0
  96. package/dist/src/extensions/Blocks/Recommendation/utils/nodeConfigWriter.d.ts +31 -0
  97. package/dist/src/extensions/Blocks/Recommendation/utils/recommendationBlockCount.d.ts +6 -2
  98. package/dist/src/extensions/Blocks/common-control.d.ts +4 -1
  99. package/dist/src/mock/api/recommendation-strategies.d.ts +2 -0
  100. package/dist/src/services/recommendationApi.d.ts +5 -1
  101. package/dist/src/stores/config.d.ts +178 -0
  102. package/dist/src/stores/save-as-template.d.ts +4 -3
  103. package/dist/src/utils/genericUtil.d.ts +5 -0
  104. package/dist/src/utils/itemsCurrencyRepair.d.ts +17 -0
  105. package/dist/static/assets/icons/filled-arrow-rising.svg.js +5 -0
  106. package/dist/static/assets/icons/line-change.svg.js +5 -0
  107. package/dist/static/assets/icons/line-delete.svg.js +5 -0
  108. package/dist/static/assets/icons/line-info.svg.js +5 -0
  109. package/dist/static/assets/icons/line-plus.svg.js +5 -0
  110. package/dist/static/styles/components/recommendation-strategy.css.js +220 -0
  111. package/dist/static/styles/customEditorStyle.css.js +3 -1
  112. package/dist/stores/config.js +66 -59
  113. package/dist/utils/dateUtil.js +23 -10
  114. package/dist/utils/genericUtil.js +28 -27
  115. package/dist/utils/itemsCurrencyRepair.js +39 -0
  116. package/dist/utils/pairProductVariables.js +58 -58
  117. package/dist/utils/templatePreparation.js +35 -34
  118. package/package.json +3 -2
  119. package/dist/composables/useModuleDynamicContentRepair.js +0 -37
  120. package/dist/src/composables/useModuleDynamicContentRepair.d.ts +0 -13
@@ -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
@@ -19,7 +20,9 @@ export * from './utils';
19
20
  export declare class RecommendationBlockControl extends CommonControl {
20
21
  private store;
21
22
  private storeUnsubscription;
22
- private syncedBlockIds;
23
+ private syncedConfigs;
24
+ private pendingNodeConfigWrite;
25
+ private pendingConfigFlushTimer;
23
26
  private algorithmControl;
24
27
  private localeControl;
25
28
  private currencyControl;
@@ -29,8 +32,12 @@ export declare class RecommendationBlockControl extends CommonControl {
29
32
  private shuffleControl;
30
33
  private pricePlacementControl;
31
34
  private layoutOrientationControl;
35
+ private strategyControl;
36
+ private rrsEnabled;
32
37
  getId(): string;
38
+ private get _subControls();
33
39
  getTemplate(): string;
40
+ private _showControlsForBlock;
34
41
  onRender(): Promise<void>;
35
42
  onTemplateNodeUpdated(node: ImmutableHtmlNode): void;
36
43
  onDestroy(): void;
@@ -42,7 +49,6 @@ export declare class RecommendationBlockControl extends CommonControl {
42
49
  /**
43
50
  * Syncs persisted node config into the Pinia store's block state.
44
51
  *
45
- * setCurrentBlock() creates a default entry (USD, en_US, mostPopular).
46
52
  * For saved templates, the real config lives in the node (e.g., TRY, tr_TR).
47
53
  * This method reads it and patches the store so fetchRecommendationProducts()
48
54
  * uses the correct values.
@@ -50,6 +56,41 @@ export declare class RecommendationBlockControl extends CommonControl {
50
56
  * Uses triggerRefetch: false because the fetch hasn't happened yet —
51
57
  * values are being prepared for the upcoming initial fetch.
52
58
  */
59
+ /**
60
+ * Re-syncs the store when the node config moved since we last read it.
61
+ *
62
+ * Undo/redo, the code editor and version-history restore rewrite the node
63
+ * config behind the store's back — Stripo exposes no undo signal, so a
64
+ * fingerprint diff on this hook is the only way to notice (SD-149105).
65
+ * An unchanged fingerprint means the move came from us, so runtime store
66
+ * edits are never clobbered (SD-141049).
67
+ */
68
+ private _syncNodeConfigIfChanged;
69
+ private _capturePendingNodeConfigWrite;
70
+ /**
71
+ * Accumulates the pending write into `documentModifier` without applying, so the
72
+ * caller's apply() commits config and re-render as ONE undo entry.
73
+ *
74
+ * Deliberately does not consume the pending record: the product helpers call
75
+ * apply() only when they actually changed something, so this batch may never be
76
+ * committed and the flush has to stay able to write it standalone.
77
+ * @param documentModifier - The batch to accumulate into
78
+ * @returns Whether anything was staged
79
+ */
80
+ private _stagePendingNodeConfig;
81
+ /**
82
+ * Arms the guaranteed fallback write, once the product fetch has settled. The
83
+ * delay only has to outlast the re-render debounce that fetch triggers — firing
84
+ * earlier writes the config on its own and the undo entry splits in two again.
85
+ */
86
+ private _scheduleConfigFlush;
87
+ private _clearConfigFlush;
88
+ /**
89
+ * Writes the deferred change standalone when the batch it was staged into never
90
+ * committed. Always targets the LIVE node — the captured one is an immutable
91
+ * snapshot the intervening re-render staled, and saveConfig swallows that failure.
92
+ */
93
+ private _flushPendingNodeConfig;
53
94
  private _syncNodeConfigToStore;
54
95
  /**
55
96
  * Fetches initial data for a block in three phases:
@@ -106,9 +147,4 @@ export declare class RecommendationBlockControl extends CommonControl {
106
147
  * We skip that tick and update tracking references instead.
107
148
  */
108
149
  private _listenStateUpdates;
109
- /**
110
- * Persists the current filter state from Pinia store to the Stripo node config.
111
- * This ensures filters survive template save/reload cycles.
112
- */
113
- private _persistFiltersToNodeConfig;
114
150
  }
@@ -0,0 +1,17 @@
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 legacyConversion;
6
+ private storeUnsubscription;
7
+ private listeners;
8
+ private lastPaintedState;
9
+ getId(): string;
10
+ getTemplate(): string;
11
+ private _strategyAction;
12
+ onRender(): void;
13
+ onDestroy(): void;
14
+ private _teardown;
15
+ private _setupButtonListeners;
16
+ private _renderState;
17
+ }
@@ -70,6 +70,7 @@ 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;
73
74
  /**
74
75
  * Regenerates only the mobile product container rows and commits in a single apply().
75
76
  * Standalone entry point for callers that change mobile-only settings
@@ -0,0 +1,86 @@
1
+ export declare const TitleControls: {
2
+ readonly align: {
3
+ new (): {
4
+ getId(): string;
5
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
6
+ getParentControlId(): string;
7
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
8
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
9
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
10
+ getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
11
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
12
+ };
13
+ };
14
+ readonly color: {
15
+ new (): {
16
+ getId(): string;
17
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
18
+ getParentControlId(): string;
19
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
20
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
21
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
22
+ getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
23
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
24
+ };
25
+ };
26
+ readonly size: {
27
+ new (): {
28
+ getId(): string;
29
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
30
+ getParentControlId(): string;
31
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
32
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
33
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
34
+ getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
35
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
36
+ };
37
+ };
38
+ readonly style: {
39
+ new (): {
40
+ getId(): string;
41
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
42
+ getParentControlId(): string;
43
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
44
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
45
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
46
+ getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
47
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
48
+ };
49
+ };
50
+ readonly fontFamily: {
51
+ new (): {
52
+ getId(): string;
53
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
54
+ getParentControlId(): string;
55
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
56
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
57
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
58
+ getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
59
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
60
+ };
61
+ };
62
+ readonly background: {
63
+ new (): {
64
+ getId(): string;
65
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
66
+ getAdditionalModifications(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
67
+ getParentControlId(): string;
68
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
69
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
70
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
71
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
72
+ };
73
+ };
74
+ readonly paddings: {
75
+ new (): {
76
+ getId(): string;
77
+ getTargetNodes(root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode[];
78
+ getParentControlId(): string;
79
+ api: import("@stripoinc/ui-editor-extensions").ControlApi;
80
+ getLabels(): import("@stripoinc/ui-editor-extensions").ControlLabels | undefined;
81
+ getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
82
+ getAdditionalModifications(_root: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
83
+ isVisible(_node: import("@stripoinc/ui-editor-extensions").ImmutableHtmlNode): boolean;
84
+ };
85
+ };
86
+ };
@@ -25,7 +25,7 @@ import { ModificationDescription } from '@stripoinc/ui-editor-extensions';
25
25
  * Stripo Extension API interface for document modifications
26
26
  * Extracted to allow type-safe usage without importing full Stripo types
27
27
  */
28
- interface DocumentModifier {
28
+ export interface DocumentModifier {
29
29
  modifyHtml: (node: ImmutableHtmlNode) => {
30
30
  setNodeConfig: (config: Record<string, unknown>) => DocumentModifier;
31
31
  setAttribute: (name: string, value: string) => DocumentModifier;
@@ -90,6 +90,17 @@ export declare class RecommendationConfigService {
90
90
  * @returns The new complete configuration
91
91
  */
92
92
  static updateConfig(api: DocumentModifierApi, node: ImmutableHtmlNode, updates: PartialNodeConfig, description: string): RecommendationNodeConfig;
93
+ /**
94
+ * Accumulate a config update into an existing modifier batch, WITHOUT applying.
95
+ *
96
+ * The caller owns the apply(), so the write shares one undo entry with the rest
97
+ * of that batch — a change whose visible result only lands after an async product
98
+ * fetch would otherwise cost the user two undo presses (SD-149105).
99
+ * @param documentModifier - The batch to accumulate into (caller applies)
100
+ * @param node - The immutable HTML node to write to
101
+ * @param updates - Partial config with values to update
102
+ */
103
+ static stageConfig(documentModifier: DocumentModifier, node: ImmutableHtmlNode, updates: PartialNodeConfig): void;
93
104
  /**
94
105
  * Initialize configuration for a new block
95
106
  *
@@ -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, RrsMigrationPayload, 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
+ strategyId: string;
25
+ nodeConfigVersion: number;
24
26
  textTrimming: boolean;
25
27
  unresponsive: boolean;
26
28
  size: string;
@@ -33,11 +35,15 @@ interface PerBlockState {
33
35
  recommendationProducts: RecommendationProduct[];
34
36
  filterStatus: boolean;
35
37
  filterSelectionDrawerStatus: boolean;
38
+ assignStrategyDrawerStatus: boolean;
39
+ removeStrategyModalStatus: boolean;
40
+ legacyStrategyUpdatedModalStatus: boolean;
36
41
  filterGroup: number;
37
42
  /** Whether initial API data (filters, algorithms, products) has been fetched for this block */
38
43
  isInitialized: boolean;
39
44
  /** Snapshot of filters taken when the drawer opens, used to revert on cancel */
40
45
  filterSnapshot: Filter[] | null;
46
+ legacyConversionLoading: boolean;
41
47
  }
42
48
  /**
43
49
  * Persisted-config subset used by `seedBlockUrlConfig` to reconstruct
@@ -47,6 +53,7 @@ interface PerBlockState {
47
53
  */
48
54
  export interface PerBlockUrlConfig {
49
55
  strategy: string;
56
+ strategyId: string;
50
57
  language: string;
51
58
  size: string;
52
59
  productIds: string[];
@@ -59,11 +66,14 @@ export interface PerBlockUrlConfig {
59
66
  currencyThousandSeparator: string;
60
67
  }
61
68
  interface StoreState {
62
- recommendationCampaignUrls: Record<string, string>;
69
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
63
70
  activePredictiveAlgorithms: number[];
64
71
  languages: Languages;
65
72
  currencyList: Currency[];
66
73
  filterList: FiltersResponse;
74
+ strategies: RrsStrategy[];
75
+ strategiesLoading: boolean;
76
+ strategyUrlTemplates: Record<string, string>;
67
77
  blockStates: Record<number, PerBlockState>;
68
78
  currentRecommendationId: number | null;
69
79
  configVersion: number;
@@ -74,7 +84,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
74
84
  * This allows all existing code that reads `store.recommendationConfigs` to work unchanged.
75
85
  */
76
86
  recommendationConfigs(state: {
77
- recommendationCampaignUrls: Record<string, string>;
87
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
78
88
  activePredictiveAlgorithms: number[];
79
89
  languages: Languages;
80
90
  currencyList: {
@@ -82,6 +92,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
82
92
  value: string;
83
93
  }[];
84
94
  filterList: FiltersResponse;
95
+ strategies: {
96
+ [x: string]: unknown;
97
+ strategy_id: number;
98
+ name: string;
99
+ status: string;
100
+ suitable_channels: string;
101
+ size?: (number | string) | undefined;
102
+ }[];
103
+ strategiesLoading: boolean;
104
+ strategyUrlTemplates: Record<string, string>;
85
105
  blockStates: Record<number, PerBlockState>;
86
106
  currentRecommendationId: number | null;
87
107
  configVersion: number;
@@ -90,7 +110,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
90
110
  * Proxy getter: delegates to blockStates[currentRecommendationId].recommendationProducts
91
111
  */
92
112
  recommendationProducts(state: {
93
- recommendationCampaignUrls: Record<string, string>;
113
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
94
114
  activePredictiveAlgorithms: number[];
95
115
  languages: Languages;
96
116
  currencyList: {
@@ -98,6 +118,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
98
118
  value: string;
99
119
  }[];
100
120
  filterList: FiltersResponse;
121
+ strategies: {
122
+ [x: string]: unknown;
123
+ strategy_id: number;
124
+ name: string;
125
+ status: string;
126
+ suitable_channels: string;
127
+ size?: (number | string) | undefined;
128
+ }[];
129
+ strategiesLoading: boolean;
130
+ strategyUrlTemplates: Record<string, string>;
101
131
  blockStates: Record<number, PerBlockState>;
102
132
  currentRecommendationId: number | null;
103
133
  configVersion: number;
@@ -106,7 +136,53 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
106
136
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterSelectionDrawerStatus
107
137
  */
108
138
  filterSelectionDrawerStatus(state: {
109
- recommendationCampaignUrls: Record<string, string>;
139
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
140
+ activePredictiveAlgorithms: number[];
141
+ languages: Languages;
142
+ currencyList: {
143
+ text: string;
144
+ value: string;
145
+ }[];
146
+ filterList: FiltersResponse;
147
+ strategies: {
148
+ [x: string]: unknown;
149
+ strategy_id: number;
150
+ name: string;
151
+ status: string;
152
+ suitable_channels: string;
153
+ size?: (number | string) | undefined;
154
+ }[];
155
+ strategiesLoading: boolean;
156
+ strategyUrlTemplates: Record<string, string>;
157
+ blockStates: Record<number, PerBlockState>;
158
+ currentRecommendationId: number | null;
159
+ configVersion: number;
160
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
161
+ assignStrategyDrawerStatus(state: {
162
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
163
+ activePredictiveAlgorithms: number[];
164
+ languages: Languages;
165
+ currencyList: {
166
+ text: string;
167
+ value: string;
168
+ }[];
169
+ filterList: FiltersResponse;
170
+ strategies: {
171
+ [x: string]: unknown;
172
+ strategy_id: number;
173
+ name: string;
174
+ status: string;
175
+ suitable_channels: string;
176
+ size?: (number | string) | undefined;
177
+ }[];
178
+ strategiesLoading: boolean;
179
+ strategyUrlTemplates: Record<string, string>;
180
+ blockStates: Record<number, PerBlockState>;
181
+ currentRecommendationId: number | null;
182
+ configVersion: number;
183
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
184
+ removeStrategyModalStatus(state: {
185
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
110
186
  activePredictiveAlgorithms: number[];
111
187
  languages: Languages;
112
188
  currencyList: {
@@ -114,15 +190,95 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
114
190
  value: string;
115
191
  }[];
116
192
  filterList: FiltersResponse;
193
+ strategies: {
194
+ [x: string]: unknown;
195
+ strategy_id: number;
196
+ name: string;
197
+ status: string;
198
+ suitable_channels: string;
199
+ size?: (number | string) | undefined;
200
+ }[];
201
+ strategiesLoading: boolean;
202
+ strategyUrlTemplates: Record<string, string>;
117
203
  blockStates: Record<number, PerBlockState>;
118
204
  currentRecommendationId: number | null;
119
205
  configVersion: number;
120
206
  } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
207
+ isLegacyStrategyBlock(): boolean;
208
+ legacyConversionLoading(state: {
209
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
210
+ activePredictiveAlgorithms: number[];
211
+ languages: Languages;
212
+ currencyList: {
213
+ text: string;
214
+ value: string;
215
+ }[];
216
+ filterList: FiltersResponse;
217
+ strategies: {
218
+ [x: string]: unknown;
219
+ strategy_id: number;
220
+ name: string;
221
+ status: string;
222
+ suitable_channels: string;
223
+ size?: (number | string) | undefined;
224
+ }[];
225
+ strategiesLoading: boolean;
226
+ strategyUrlTemplates: Record<string, string>;
227
+ blockStates: Record<number, PerBlockState>;
228
+ currentRecommendationId: number | null;
229
+ configVersion: number;
230
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
231
+ legacyStrategyUpdatedModalStatus(state: {
232
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
233
+ activePredictiveAlgorithms: number[];
234
+ languages: Languages;
235
+ currencyList: {
236
+ text: string;
237
+ value: string;
238
+ }[];
239
+ filterList: FiltersResponse;
240
+ strategies: {
241
+ [x: string]: unknown;
242
+ strategy_id: number;
243
+ name: string;
244
+ status: string;
245
+ suitable_channels: string;
246
+ size?: (number | string) | undefined;
247
+ }[];
248
+ strategiesLoading: boolean;
249
+ strategyUrlTemplates: Record<string, string>;
250
+ blockStates: Record<number, PerBlockState>;
251
+ currentRecommendationId: number | null;
252
+ configVersion: number;
253
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): boolean;
254
+ assignedStrategy(state: {
255
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
256
+ activePredictiveAlgorithms: number[];
257
+ languages: Languages;
258
+ currencyList: {
259
+ text: string;
260
+ value: string;
261
+ }[];
262
+ filterList: FiltersResponse;
263
+ strategies: {
264
+ [x: string]: unknown;
265
+ strategy_id: number;
266
+ name: string;
267
+ status: string;
268
+ suitable_channels: string;
269
+ size?: (number | string) | undefined;
270
+ }[];
271
+ strategiesLoading: boolean;
272
+ strategyUrlTemplates: Record<string, string>;
273
+ blockStates: Record<number, PerBlockState>;
274
+ currentRecommendationId: number | null;
275
+ configVersion: number;
276
+ } & import("pinia").PiniaCustomStateProperties<StoreState>): RrsStrategy | null;
121
277
  /**
122
278
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterStatus
123
279
  */
124
280
  filterStatus(state: {
125
- recommendationCampaignUrls: Record<string, string>;
281
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
126
282
  activePredictiveAlgorithms: number[];
127
283
  languages: Languages;
128
284
  currencyList: {
@@ -130,6 +286,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
130
286
  value: string;
131
287
  }[];
132
288
  filterList: FiltersResponse;
289
+ strategies: {
290
+ [x: string]: unknown;
291
+ strategy_id: number;
292
+ name: string;
293
+ status: string;
294
+ suitable_channels: string;
295
+ size?: (number | string) | undefined;
296
+ }[];
297
+ strategiesLoading: boolean;
298
+ strategyUrlTemplates: Record<string, string>;
133
299
  blockStates: Record<number, PerBlockState>;
134
300
  currentRecommendationId: number | null;
135
301
  configVersion: number;
@@ -138,7 +304,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
138
304
  * Proxy getter: delegates to blockStates[currentRecommendationId].filterGroup
139
305
  */
140
306
  filterGroup(state: {
141
- recommendationCampaignUrls: Record<string, string>;
307
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
142
308
  activePredictiveAlgorithms: number[];
143
309
  languages: Languages;
144
310
  currencyList: {
@@ -146,6 +312,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
146
312
  value: string;
147
313
  }[];
148
314
  filterList: FiltersResponse;
315
+ strategies: {
316
+ [x: string]: unknown;
317
+ strategy_id: number;
318
+ name: string;
319
+ status: string;
320
+ suitable_channels: string;
321
+ size?: (number | string) | undefined;
322
+ }[];
323
+ strategiesLoading: boolean;
324
+ strategyUrlTemplates: Record<string, string>;
149
325
  blockStates: Record<number, PerBlockState>;
150
326
  currentRecommendationId: number | null;
151
327
  configVersion: number;
@@ -155,7 +331,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
155
331
  getFilterGroupCount(): number;
156
332
  getUniqueFilterGroups(): number[];
157
333
  getActivePredictiveAlgorithms: (state: {
158
- recommendationCampaignUrls: Record<string, string>;
334
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
159
335
  activePredictiveAlgorithms: number[];
160
336
  languages: Languages;
161
337
  currencyList: {
@@ -163,6 +339,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
163
339
  value: string;
164
340
  }[];
165
341
  filterList: FiltersResponse;
342
+ strategies: {
343
+ [x: string]: unknown;
344
+ strategy_id: number;
345
+ name: string;
346
+ status: string;
347
+ suitable_channels: string;
348
+ size?: (number | string) | undefined;
349
+ }[];
350
+ strategiesLoading: boolean;
351
+ strategyUrlTemplates: Record<string, string>;
166
352
  blockStates: Record<number, PerBlockState>;
167
353
  currentRecommendationId: number | null;
168
354
  configVersion: number;
@@ -171,7 +357,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
171
357
  value: string;
172
358
  }[];
173
359
  getLanguages: (state: {
174
- recommendationCampaignUrls: Record<string, string>;
360
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
175
361
  activePredictiveAlgorithms: number[];
176
362
  languages: Languages;
177
363
  currencyList: {
@@ -179,6 +365,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
179
365
  value: string;
180
366
  }[];
181
367
  filterList: FiltersResponse;
368
+ strategies: {
369
+ [x: string]: unknown;
370
+ strategy_id: number;
371
+ name: string;
372
+ status: string;
373
+ suitable_channels: string;
374
+ size?: (number | string) | undefined;
375
+ }[];
376
+ strategiesLoading: boolean;
377
+ strategyUrlTemplates: Record<string, string>;
182
378
  blockStates: Record<number, PerBlockState>;
183
379
  currentRecommendationId: number | null;
184
380
  configVersion: number;
@@ -187,7 +383,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
187
383
  value: string;
188
384
  }[];
189
385
  getCurrencySymbolList: (state: {
190
- recommendationCampaignUrls: Record<string, string>;
386
+ recommendationCampaignUrls: Record<string, RecommendationCampaignUrlValue>;
191
387
  activePredictiveAlgorithms: number[];
192
388
  languages: Languages;
193
389
  currencyList: {
@@ -195,6 +391,16 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
195
391
  value: string;
196
392
  }[];
197
393
  filterList: FiltersResponse;
394
+ strategies: {
395
+ [x: string]: unknown;
396
+ strategy_id: number;
397
+ name: string;
398
+ status: string;
399
+ suitable_channels: string;
400
+ size?: (number | string) | undefined;
401
+ }[];
402
+ strategiesLoading: boolean;
403
+ strategyUrlTemplates: Record<string, string>;
198
404
  blockStates: Record<number, PerBlockState>;
199
405
  currentRecommendationId: number | null;
200
406
  configVersion: number;
@@ -272,6 +478,17 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
272
478
  * to the snapshot taken when the drawer was opened.
273
479
  */
274
480
  cancelFilterDrawer(): void;
481
+ openAssignStrategyDrawer(): void;
482
+ closeAssignStrategyDrawer(): void;
483
+ openLegacyStrategyUpdatedModal(): void;
484
+ closeLegacyStrategyUpdatedModal(): void;
485
+ openRemoveStrategyModal(): void;
486
+ closeRemoveStrategyModal(): void;
487
+ fetchStrategies(): Promise<void>;
488
+ resolveStrategyUrlTemplate(strategy: RrsStrategy, currency: string): Promise<string>;
489
+ assignStrategy(strategy: RrsStrategy): void;
490
+ convertLegacyStrategy(payload: RrsMigrationPayload): Promise<string>;
491
+ removeStrategy(): void;
275
492
  fetchRecommendationCreateData(): Promise<void>;
276
493
  fetchRecommendationFilters(): Promise<void>;
277
494
  addFilterGroup(filterGroup: number): void;
@@ -288,5 +505,7 @@ export declare const useRecommendationExtensionStore: import("pinia").StoreDefin
288
505
  hasInvalidBlock(): boolean;
289
506
  fetchRecommendationProducts(): Promise<void>;
290
507
  _doFetchProducts(): Promise<void>;
508
+ _doFetchStrategyProducts(blockId: number): Promise<void>;
509
+ _setBlockProducts(blockId: number, products: RecommendationProduct[], size: number): void;
291
510
  }>;
292
511
  export {};
@@ -0,0 +1,13 @@
1
+ export declare const DEFAULT_TITLE_TEXT = "You May Also Like!";
2
+ export declare const DEFAULT_TITLE_PARAGRAPH: string;
3
+ /**
4
+ * Builds the two block-level title rows: the title itself and the spacer below it.
5
+ * Both carry the same `recommendation-attribute-row` tagging a card attribute row has,
6
+ * so the Card Composition toggle hides the pair together and the compiler's
7
+ * `[data-visibility="0"]` sweep drops both — no leading gap when the title is off.
8
+ * @param paragraphHtml - Full `<p>` markup rendered inside the title cell
9
+ * @param visible - Whether the title starts visible
10
+ * @param spacerHeightPx - Height of the spacer row below the title
11
+ * @returns HTML string with the title row followed by its spacer row
12
+ */
13
+ export declare function buildTitleRows(paragraphHtml?: string, visible?: boolean, spacerHeightPx?: number): string;
@@ -82,6 +82,7 @@ export interface RecommendationNodeConfig {
82
82
  * Uses existing Filter interface from recommendation types
83
83
  */
84
84
  filters: Filter[];
85
+ strategyId: string;
85
86
  /**
86
87
  * Layout orientation
87
88
  * - 'grid': Products in a grid, attributes aligned across products
@@ -138,6 +139,12 @@ export interface RecommendationNodeConfig {
138
139
  * Keys are ATTR_PRODUCT_* constants
139
140
  */
140
141
  visibility: Record<string, boolean>;
142
+ /**
143
+ * Snapshot of the block title's row markup before it's removed.
144
+ * Restored verbatim when the title is re-enabled.
145
+ * @default ''
146
+ */
147
+ previousTitleHtml: string;
141
148
  /**
142
149
  * Omnibus price text configuration
143
150
  * For EU Omnibus Directive compliance