@useinsider/guido 3.12.0-beta.841bb6a → 3.12.0-beta.86e34da
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/@types/config/schemas.js +9 -4
- package/dist/components/Guido.vue.js +6 -6
- package/dist/components/Guido.vue2.js +50 -49
- package/dist/components/organisms/email-preview/desktop-preview/DesktopPreview.vue.js +1 -1
- package/dist/components/organisms/email-preview/desktop-preview/DesktopPreview.vue2.js +8 -8
- package/dist/components/organisms/email-preview/mobile-preview/ContentView.vue.js +5 -5
- package/dist/components/organisms/email-preview/mobile-preview/ContentView.vue2.js +10 -10
- package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.js +38 -0
- package/dist/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue2.js +271 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.js +18 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue2.js +42 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.js +20 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue2.js +18 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.js +20 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue2.js +60 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.js +19 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue2.js +19 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.js +22 -0
- package/dist/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue2.js +29 -0
- package/dist/composables/usePreviewInteractionGuard.js +36 -11
- package/dist/composables/useRecommendation.js +56 -40
- package/dist/composables/useRecommendationPreview.js +61 -60
- package/dist/composables/useStrategyFilters.js +16 -0
- package/dist/config/migrator/recommendationMigrator.js +7 -4
- package/dist/enums/date.js +4 -3
- package/dist/enums/extensions/filteringV2.js +1024 -0
- package/dist/enums/extensions/recommendationBlock.js +45 -24
- package/dist/enums/extensions/strategyDetail.js +148 -0
- package/dist/extensions/Blocks/Recommendation/constants/controlIds.js +1 -1
- package/dist/extensions/Blocks/Recommendation/constants/defaultConfig.js +12 -11
- package/dist/extensions/Blocks/Recommendation/controls/blockBackground/index.js +10 -0
- package/dist/extensions/Blocks/Recommendation/controls/main/index.js +141 -123
- package/dist/extensions/Blocks/Recommendation/controls/main/strategy.js +285 -0
- package/dist/extensions/Blocks/Recommendation/extension.js +23 -21
- package/dist/extensions/Blocks/Recommendation/iconsRegistry.js +16 -2
- package/dist/extensions/Blocks/Recommendation/recommendation.css.js +257 -0
- package/dist/extensions/Blocks/Recommendation/settingsPanel.js +41 -40
- package/dist/extensions/Blocks/Recommendation/store/recommendation.js +460 -113
- package/dist/extensions/Blocks/Recommendation/utils/strategyHumanizer.js +97 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategyNavigation.js +8 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategySummary.js +95 -0
- package/dist/extensions/Blocks/Recommendation/utils/strategyUrl.js +43 -0
- package/dist/extensions/Blocks/Recommendation/validation/requiredFields.js +24 -10
- package/dist/extensions/Blocks/Unsubscribe/utils/constants.js +3 -2
- package/dist/extensions/Blocks/common-control.js +2 -1
- package/dist/extensions/Blocks/controlFactories.js +125 -75
- package/dist/guido.css +1 -1
- package/dist/services/recommendationApi.js +120 -32
- package/dist/services/stripoApi.js +18 -18
- package/dist/src/@types/config/schemas.d.ts +10 -0
- package/dist/src/components/organisms/extensions/recommendation/StrategyDetailDrawer.vue.d.ts +2 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/CampaignTable.vue.d.ts +43 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/FilterHumanizer.vue.d.ts +29 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerCondition.vue.d.ts +40 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/HumanizerGroup.vue.d.ts +38 -0
- package/dist/src/components/organisms/extensions/recommendation/strategy-detail/InfoDisplayValue.vue.d.ts +51 -0
- package/dist/src/composables/useConfig.d.ts +2 -0
- package/dist/src/composables/usePreviewInteractionGuard.d.ts +1 -1
- package/dist/src/composables/useRecommendation.d.ts +2 -0
- package/dist/src/composables/useStrategyFilters.d.ts +24 -0
- package/dist/src/enums/extensions/filteringV2.d.ts +72 -0
- package/dist/src/enums/extensions/recommendationBlock.d.ts +33 -0
- package/dist/src/enums/extensions/strategyDetail.d.ts +90 -0
- package/dist/src/extensions/Blocks/Recommendation/constants/controlIds.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/blockBackground/index.d.ts +14 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/index.d.ts +1 -0
- package/dist/src/extensions/Blocks/Recommendation/controls/main/index.d.ts +10 -4
- package/dist/src/extensions/Blocks/Recommendation/controls/main/strategy.d.ts +75 -0
- package/dist/src/extensions/Blocks/Recommendation/store/recommendation.d.ts +903 -1
- package/dist/src/extensions/Blocks/Recommendation/types/nodeConfig.d.ts +7 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyHumanizer.d.ts +50 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyNavigation.d.ts +10 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategySummary.d.ts +34 -0
- package/dist/src/extensions/Blocks/Recommendation/utils/strategyUrl.d.ts +51 -0
- package/dist/src/extensions/Blocks/Recommendation/validation/requiredFields.d.ts +8 -1
- package/dist/src/extensions/Blocks/Unsubscribe/utils/constants.d.ts +1 -0
- package/dist/src/extensions/Blocks/common-control.d.ts +2 -1
- package/dist/src/extensions/Blocks/controlFactories.d.ts +36 -0
- package/dist/src/mock/api/recommendation-strategies.d.ts +2 -0
- package/dist/src/services/recommendationApi.d.ts +9 -1
- package/dist/src/stores/config.d.ts +18 -0
- package/dist/src/utils/genericUtil.d.ts +9 -0
- package/dist/src/utils/urlSchemes.d.ts +6 -0
- package/dist/static/styles/components/base-input.css.js +6 -7
- package/dist/utils/dateUtil.js +23 -10
- package/dist/utils/genericUtil.js +10 -1
- package/dist/utils/pairProductVariables.js +43 -44
- package/dist/utils/templatePreparation.js +70 -57
- package/dist/utils/urlSchemes.js +4 -0
- package/package.json +1 -1
|
@@ -54,6 +54,13 @@ export interface RecommendationNodeConfig {
|
|
|
54
54
|
* @example 'mostPopular', 'complementaryItems', 'manualMerchandising'
|
|
55
55
|
*/
|
|
56
56
|
strategy: string;
|
|
57
|
+
/**
|
|
58
|
+
* Reusable Recommendation Strategy (RRS) id from Smart Recommender.
|
|
59
|
+
* Empty string means no strategy is assigned.
|
|
60
|
+
* Only used when the `reusableRecommendationStrategy` feature is enabled;
|
|
61
|
+
* when set, it supersedes `strategy` for building the recommendation URL.
|
|
62
|
+
*/
|
|
63
|
+
strategyId: string;
|
|
57
64
|
/**
|
|
58
65
|
* Product IDs for manual merchandising strategy
|
|
59
66
|
* Only used when strategy === 'manualMerchandising'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders one RRS filter condition as readable text for the detail drawer.
|
|
3
|
+
*
|
|
4
|
+
* Ported from design-system-organisms
|
|
5
|
+
* `src/organisms/OrgStrategyDetailModal/helpers/humanizer.helper.ts` (branch `develop`).
|
|
6
|
+
*
|
|
7
|
+
* Two deliberate deviations from the source:
|
|
8
|
+
*
|
|
9
|
+
* 1. `trans` is injected rather than read from a module-level `translations` object,
|
|
10
|
+
* so this stays pure and testable and picks up Guido's editor-config translations.
|
|
11
|
+
* 2. The source wraps every date in `getUnixTimestampFromDate(...)` before formatting.
|
|
12
|
+
* Guido's `formatShortDate` already accepts a raw date string via
|
|
13
|
+
* `convertToDateObject`, so that conversion hop is dropped rather than reimplemented.
|
|
14
|
+
*
|
|
15
|
+
* This humanizes the same JSON as `strategySummary.ts` but for a different surface —
|
|
16
|
+
* see the note in `@@/Enums/extensions/strategyDetail` on why the operator tables differ.
|
|
17
|
+
*/
|
|
18
|
+
import type { RrsDetailCondition } from '@@/Types/recommendation';
|
|
19
|
+
/** Translation lookup, matching `useTranslations()`. */
|
|
20
|
+
type TranslateFn = (key: string, params?: Record<string, string | number | boolean>) => string;
|
|
21
|
+
export interface TimeUnitOption {
|
|
22
|
+
text: string;
|
|
23
|
+
value: string;
|
|
24
|
+
}
|
|
25
|
+
export declare const capitalizeFirstLetter: (text: string) => string;
|
|
26
|
+
export declare const getUserEventLabel: (userEvent: string, trans: TranslateFn) => string;
|
|
27
|
+
/** Describes a user-attribute or user-event condition, e.g. "Users' last viewed 3 items". */
|
|
28
|
+
export declare const getUserContextValue: (condition: RrsDetailCondition, trans: TranslateFn) => string;
|
|
29
|
+
/** Renders a `7d`-style duration as " in last 7 days", or '' when absent or malformed. */
|
|
30
|
+
export declare const getDurationSuffix: (duration: string | undefined, timeUnitOptions: TimeUnitOption[], trans: TranslateFn) => string;
|
|
31
|
+
export interface SuitableValueParams {
|
|
32
|
+
condition: RrsDetailCondition;
|
|
33
|
+
selectedOperator: string;
|
|
34
|
+
filterValue: string;
|
|
35
|
+
timeUnit: string;
|
|
36
|
+
inBetweenValues: string[];
|
|
37
|
+
timeUnitOptions: TimeUnitOption[];
|
|
38
|
+
isDateAttribute: () => boolean;
|
|
39
|
+
isMultiSelect: () => boolean;
|
|
40
|
+
isInOrNotInOperator: () => boolean;
|
|
41
|
+
trans: TranslateFn;
|
|
42
|
+
}
|
|
43
|
+
export declare const bracketJoin: (items: string[], and: string) => string;
|
|
44
|
+
/**
|
|
45
|
+
* A multi-select condition stores its values either as a JSON array or, on older
|
|
46
|
+
* strategies, as a bare comma-separated string. Both must humanize the same way.
|
|
47
|
+
*/
|
|
48
|
+
export declare const parseMultiSelectValue: (value: string) => string[];
|
|
49
|
+
export declare function getSuitableValue(params: SuitableValueParams): string;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Recommender pages live outside the editor. The task spec is explicit that
|
|
3
|
+
* Create and Edit open in the *same* tab and that the flow finishes over there —
|
|
4
|
+
* there is no return trip, so nothing is stashed before leaving.
|
|
5
|
+
*
|
|
6
|
+
* ponytail: a full page load, not a router push. Guido has no router and is
|
|
7
|
+
* embedded in inone; whatever unload handling the host registers still applies.
|
|
8
|
+
*/
|
|
9
|
+
export declare const navigateToStrategyPage: (path: string) => void;
|
|
10
|
+
export declare const buildStrategyEditPath: (id: string | number) => string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human-readable summary of a Reusable Recommendation Strategy (RRS).
|
|
3
|
+
*
|
|
4
|
+
* Ported from discovery-strategies-fe
|
|
5
|
+
* `src/components/atoms/GptAppBuilder/StrategyInfoBoxContent.composition.vue`.
|
|
6
|
+
*
|
|
7
|
+
* The source is a Vue SFC whose template is fourteen lines of plain `<div>`s over
|
|
8
|
+
* a `{ title, value }[]` computed. Only the computed carries meaning, so the port
|
|
9
|
+
* is a pure function instead: the panel renders it as an HTML string and the
|
|
10
|
+
* detail drawer renders it as components, both from this one implementation.
|
|
11
|
+
*
|
|
12
|
+
* Produces four rows — Algorithms and Method, Exclusions, Filters, Manual
|
|
13
|
+
* Merchandising — each truncated with "and N more." and falling back to
|
|
14
|
+
* `recommendation-strategy.none` when empty.
|
|
15
|
+
*
|
|
16
|
+
* `trans` is injected rather than pulled from `useTranslations()` so this stays a
|
|
17
|
+
* pure function: no composable lifetime to reason about, and tests need no config.
|
|
18
|
+
*/
|
|
19
|
+
import type { RrsStrategy, RrsSummaryRow } from '@@/Types/recommendation';
|
|
20
|
+
/** Translation lookup, matching `useTranslations().trans`. */
|
|
21
|
+
type TranslateFn = (key: string, params?: Record<string, string | number | boolean>) => string;
|
|
22
|
+
/**
|
|
23
|
+
* `TOP_SELLERS` -> `recommendation-algorithm-names.top-sellers`.
|
|
24
|
+
* A pure string transform — Smart Recommender has no algorithm lookup table.
|
|
25
|
+
*/
|
|
26
|
+
export declare const getAlgorithmTranslationKey: (algorithm: string) => string;
|
|
27
|
+
export declare const getMethodTranslationKey: (algorithm: string) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Builds the four-row summary shown beside the strategy dropdown.
|
|
30
|
+
* @param strategy - A strategy row as returned by the RRS listing endpoint.
|
|
31
|
+
* @param trans - Translation lookup, e.g. `useTranslations().trans`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const buildStrategySummary: (strategy: RrsStrategy, trans: TranslateFn) => RrsSummaryRow[];
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Placeholder substitution for a strategy's product-feed URL.
|
|
3
|
+
*
|
|
4
|
+
* Smart Recommender's `endpoint-generate` answers one template per strategy with
|
|
5
|
+
* tokens left in it. The same template drives two consumers with different rules,
|
|
6
|
+
* which is why this lives outside `useRecommendation` (the store would otherwise
|
|
7
|
+
* import the composable that imports the store):
|
|
8
|
+
*
|
|
9
|
+
* compile — the URL is baked into the email. Per-recipient tokens must survive
|
|
10
|
+
* as merge tags, and anything we cannot resolve is left for the ESP.
|
|
11
|
+
* preview — the URL is fetched right now, in the editor. Per-recipient tokens
|
|
12
|
+
* have no value yet, and a leftover `{token}` would be sent literally,
|
|
13
|
+
* so those params are dropped.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Tokens carrying a value the editor knows. Two spellings exist in the wild for
|
|
17
|
+
* the same thing — the web runtime's templates write `{language}`/`{partnerId}`,
|
|
18
|
+
* the Smart Recommender previewer writes `{locale}`/`{partnerName}` — so both are
|
|
19
|
+
* substituted rather than guessing which one a given template used.
|
|
20
|
+
*/
|
|
21
|
+
declare const RESOLVED_PLACEHOLDERS: {
|
|
22
|
+
readonly LOCALE: readonly ["{locale}", "{language}"];
|
|
23
|
+
readonly CURRENCY: readonly ["{currency}"];
|
|
24
|
+
readonly CAMPAIGN_ID: readonly ["{campaignId}"];
|
|
25
|
+
readonly STRATEGY_ID: readonly ["{strategyId}"];
|
|
26
|
+
readonly CLIENT_ID: readonly ["{clientId}"];
|
|
27
|
+
readonly PARTNER_NAME: readonly ["{partnerName}", "{partnerId}"];
|
|
28
|
+
readonly SIZE: readonly ["{size}"];
|
|
29
|
+
};
|
|
30
|
+
export type StrategyUrlValues = Record<keyof typeof RESOLVED_PLACEHOLDERS, string>;
|
|
31
|
+
export type StrategyUrlMode = 'compile' | 'preview';
|
|
32
|
+
/**
|
|
33
|
+
* Collect the token values from the block's config plus the editor's own context.
|
|
34
|
+
*
|
|
35
|
+
* Shared so the compiled URL and the canvas preview cannot drift: the preview is
|
|
36
|
+
* only trustworthy if it is the *same* URL the email will carry.
|
|
37
|
+
*/
|
|
38
|
+
export declare const buildStrategyUrlValues: (block: {
|
|
39
|
+
language: string;
|
|
40
|
+
currencyCode: string;
|
|
41
|
+
size: string;
|
|
42
|
+
strategyId: string;
|
|
43
|
+
}) => StrategyUrlValues;
|
|
44
|
+
/**
|
|
45
|
+
* Substitute the editor-owned tokens in a strategy feed template.
|
|
46
|
+
*
|
|
47
|
+
* Unknown tokens are preserved in `compile` mode — an unknown token means someone
|
|
48
|
+
* downstream owns it, and blanking it would silently corrupt the feed URL.
|
|
49
|
+
*/
|
|
50
|
+
export declare const resolveStrategyUrl: (template: string, values: StrategyUrlValues, mode: StrategyUrlMode) => string;
|
|
51
|
+
export {};
|
|
@@ -7,13 +7,20 @@ import type { Currency, Languages } from '@@/Types/recommendation';
|
|
|
7
7
|
export interface ExtensionStoreSlice {
|
|
8
8
|
languages: Languages;
|
|
9
9
|
currencyList: Currency[];
|
|
10
|
+
/** Whether the `reusableRecommendationStrategy` feature is enabled. */
|
|
11
|
+
isRrsEnabled: boolean;
|
|
12
|
+
/** Ids of the strategies Smart Recommender currently offers for email. */
|
|
13
|
+
strategyIds: string[];
|
|
14
|
+
/** False while the strategy listing is unavailable, when nothing can be judged. */
|
|
15
|
+
canValidateStrategy: boolean;
|
|
10
16
|
}
|
|
11
17
|
export interface RequiredField {
|
|
12
18
|
key: string;
|
|
13
19
|
canBeEmpty?: boolean;
|
|
20
|
+
optional?: boolean;
|
|
14
21
|
getValue: (config: PerBlockConfigs) => string;
|
|
15
22
|
getAvailableOptions?: (store: ExtensionStoreSlice) => string[];
|
|
16
|
-
condition?: (config: PerBlockConfigs) => boolean;
|
|
23
|
+
condition?: (config: PerBlockConfigs, store: ExtensionStoreSlice) => boolean;
|
|
17
24
|
}
|
|
18
25
|
export declare const REQUIRED_RECOMMENDATION_FIELDS: RequiredField[];
|
|
19
26
|
export declare const RecommendationRequiredFieldsKey = "newsletter.recommendation-fill-required-fields";
|
|
@@ -9,3 +9,4 @@ export declare const DATA_ATTRIBUTES: {
|
|
|
9
9
|
readonly BLOCK_ID: "data-unsubscribe-block-id";
|
|
10
10
|
};
|
|
11
11
|
export declare const UNSUBSCRIBE_BLOCK_SELECTOR = ".unsubscribe-block-v2";
|
|
12
|
+
export declare const UNSUBSCRIBE_LINK_SELECTOR = "a[data-unsubscribe-link=\"true\"], a.unsubscribe-link";
|
|
@@ -28,6 +28,7 @@ interface IconButtonProps {
|
|
|
28
28
|
name: string;
|
|
29
29
|
icon: string;
|
|
30
30
|
className?: string;
|
|
31
|
+
id?: string;
|
|
31
32
|
}
|
|
32
33
|
interface SelectProps {
|
|
33
34
|
name: string;
|
|
@@ -121,7 +122,7 @@ export declare abstract class CommonControl extends Control {
|
|
|
121
122
|
* @param param0
|
|
122
123
|
* @returns It returns a button with an icon.
|
|
123
124
|
*/
|
|
124
|
-
_GuIconButton({ name, icon, className }: IconButtonProps): string;
|
|
125
|
+
_GuIconButton({ name, icon, className, id }: IconButtonProps): string;
|
|
125
126
|
_GuOneColumn(children: string[], className?: string): string;
|
|
126
127
|
_GuTwoColumns(children: string[], className?: string): string;
|
|
127
128
|
/**
|
|
@@ -115,6 +115,42 @@ export declare function createTextBackgroundColorControl(controlId: string, targ
|
|
|
115
115
|
isVisible(_node: ImmutableHtmlNode): boolean;
|
|
116
116
|
};
|
|
117
117
|
};
|
|
118
|
+
/**
|
|
119
|
+
* Factory for a background-color control that paints a whole extension block (SD-145082).
|
|
120
|
+
*
|
|
121
|
+
* Base is `ButtonBackgroundColorBuiltInControl` because its `GENERAL.BACKGROUND_COLOR` form key
|
|
122
|
+
* round-trips through `getValues()`; the block-text base (`TextBlockBackgroundBuiltInControl`, the
|
|
123
|
+
* built-in this replaces) reports `textBlockBackgroundColor`, which our read path never sees. That
|
|
124
|
+
* borrowed base targets the block's Buy buttons, so `getTargetNodes` here is a GUARD that keeps it
|
|
125
|
+
* off the buttons — not the write path.
|
|
126
|
+
*
|
|
127
|
+
* The write is entirely ours (`getAdditionalModifications`): Stripo's built-in emits a stylesheet
|
|
128
|
+
* rule that inline styles from regeneration outrank (SD-143023), so it would silently no-op on the
|
|
129
|
+
* next edit. We write inline `background-color` + `bgcolor` on the block `<td>` instead — surviving
|
|
130
|
+
* regeneration and reaching Outlook, matching the migrator's convention.
|
|
131
|
+
*/
|
|
132
|
+
export declare function createBlockBackgroundColorControl(controlId: string, blockRootSelector?: string): {
|
|
133
|
+
new (): {
|
|
134
|
+
getId(): string;
|
|
135
|
+
/** The parent control renders its own generic title; restore the block-level wording. */
|
|
136
|
+
getLabels(): {
|
|
137
|
+
title: string;
|
|
138
|
+
};
|
|
139
|
+
/** Guard: redirect the borrowed button parent onto the block `<td>` so it never paints the Buy buttons. */
|
|
140
|
+
getTargetNodes(root: ImmutableHtmlNode): ImmutableHtmlNode[];
|
|
141
|
+
/**
|
|
142
|
+
* Writes the picked background onto the block as an inline style plus a `bgcolor`
|
|
143
|
+
* attribute. This is the whole mechanism, not a mirror: the parent control's own
|
|
144
|
+
* write never reaches the block element (verified at runtime). `bgcolor` is the
|
|
145
|
+
* channel Outlook honours on a `<td>`, and matches what the migrator emits.
|
|
146
|
+
*/
|
|
147
|
+
getAdditionalModifications(root: ImmutableHtmlNode): import("@stripoinc/ui-editor-extensions").TemplateModifier<import("@stripoinc/ui-editor-extensions").HtmlNodeModifier, import("@stripoinc/ui-editor-extensions").CssNodeModifier> | undefined;
|
|
148
|
+
getParentControlId(): string;
|
|
149
|
+
api: import("@stripoinc/ui-editor-extensions").ControlApi;
|
|
150
|
+
getModificationDescription(): import("@stripoinc/ui-editor-extensions").ModificationDescription | undefined;
|
|
151
|
+
isVisible(_node: ImmutableHtmlNode): boolean;
|
|
152
|
+
};
|
|
153
|
+
};
|
|
118
154
|
/**
|
|
119
155
|
* Factory function to create paddings controls for different block elements
|
|
120
156
|
* When targetBlockId and containerSelector are not provided, applies directly to root
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
import type { InitialResponse, FiltersResponse, RecommendationProduct, RecommendationProductsParams } from '@@/Types/recommendation';
|
|
1
|
+
import type { InitialResponse, FiltersResponse, RecommendationProduct, RecommendationProductsParams, RrsCampaign, RrsStrategy, RrsStrategyUrl } from '@@/Types/recommendation';
|
|
2
|
+
/** Translation lookup, matching `useTranslations()`. */
|
|
3
|
+
type TranslateFn = (key: string, params?: Record<string, string | number | boolean>) => string;
|
|
2
4
|
export declare const useRecommendationApi: () => {
|
|
5
|
+
duplicateStrategy: (strategyId: string) => Promise<string | null>;
|
|
3
6
|
fetchRecommendationCreateData: () => Promise<InitialResponse>;
|
|
4
7
|
fetchRecommendationFilters: () => Promise<FiltersResponse>;
|
|
5
8
|
fetchRecommendationProducts: (strategy: string, params: RecommendationProductsParams) => Promise<RecommendationProduct[]>;
|
|
9
|
+
fetchRecommendationProductsByUrl: (url: string) => Promise<RecommendationProduct[]>;
|
|
10
|
+
fetchRecommendationStrategies: () => Promise<RrsStrategy[]>;
|
|
11
|
+
fetchStrategyCampaigns: (strategyId: string, trans: TranslateFn) => Promise<RrsCampaign[]>;
|
|
12
|
+
generateStrategyEndpoint: (strategy: RrsStrategy, campaignId: string) => Promise<RrsStrategyUrl | null>;
|
|
6
13
|
};
|
|
14
|
+
export {};
|
|
@@ -101,6 +101,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
101
101
|
modulesDisabled: boolean;
|
|
102
102
|
liquidSyntax: boolean;
|
|
103
103
|
autosave: boolean;
|
|
104
|
+
reusableRecommendationStrategy: boolean;
|
|
104
105
|
};
|
|
105
106
|
blocks: {
|
|
106
107
|
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")[];
|
|
@@ -238,6 +239,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
238
239
|
modulesDisabled: boolean;
|
|
239
240
|
liquidSyntax: boolean;
|
|
240
241
|
autosave: boolean;
|
|
242
|
+
reusableRecommendationStrategy: boolean;
|
|
241
243
|
};
|
|
242
244
|
blocks: {
|
|
243
245
|
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")[];
|
|
@@ -375,6 +377,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
375
377
|
modulesDisabled: boolean;
|
|
376
378
|
liquidSyntax: boolean;
|
|
377
379
|
autosave: boolean;
|
|
380
|
+
reusableRecommendationStrategy: boolean;
|
|
378
381
|
};
|
|
379
382
|
blocks: {
|
|
380
383
|
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")[];
|
|
@@ -512,6 +515,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
512
515
|
modulesDisabled: boolean;
|
|
513
516
|
liquidSyntax: boolean;
|
|
514
517
|
autosave: boolean;
|
|
518
|
+
reusableRecommendationStrategy: boolean;
|
|
515
519
|
};
|
|
516
520
|
blocks: {
|
|
517
521
|
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")[];
|
|
@@ -649,6 +653,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
649
653
|
modulesDisabled: boolean;
|
|
650
654
|
liquidSyntax: boolean;
|
|
651
655
|
autosave: boolean;
|
|
656
|
+
reusableRecommendationStrategy: boolean;
|
|
652
657
|
};
|
|
653
658
|
blocks: {
|
|
654
659
|
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")[];
|
|
@@ -786,6 +791,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
786
791
|
modulesDisabled: boolean;
|
|
787
792
|
liquidSyntax: boolean;
|
|
788
793
|
autosave: boolean;
|
|
794
|
+
reusableRecommendationStrategy: boolean;
|
|
789
795
|
};
|
|
790
796
|
blocks: {
|
|
791
797
|
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")[];
|
|
@@ -923,6 +929,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
923
929
|
modulesDisabled: boolean;
|
|
924
930
|
liquidSyntax: boolean;
|
|
925
931
|
autosave: boolean;
|
|
932
|
+
reusableRecommendationStrategy: boolean;
|
|
926
933
|
};
|
|
927
934
|
blocks: {
|
|
928
935
|
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")[];
|
|
@@ -1060,6 +1067,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1060
1067
|
modulesDisabled: boolean;
|
|
1061
1068
|
liquidSyntax: boolean;
|
|
1062
1069
|
autosave: boolean;
|
|
1070
|
+
reusableRecommendationStrategy: boolean;
|
|
1063
1071
|
};
|
|
1064
1072
|
blocks: {
|
|
1065
1073
|
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")[];
|
|
@@ -1197,6 +1205,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1197
1205
|
modulesDisabled: boolean;
|
|
1198
1206
|
liquidSyntax: boolean;
|
|
1199
1207
|
autosave: boolean;
|
|
1208
|
+
reusableRecommendationStrategy: boolean;
|
|
1200
1209
|
};
|
|
1201
1210
|
blocks: {
|
|
1202
1211
|
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")[];
|
|
@@ -1334,6 +1343,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1334
1343
|
modulesDisabled: boolean;
|
|
1335
1344
|
liquidSyntax: boolean;
|
|
1336
1345
|
autosave: boolean;
|
|
1346
|
+
reusableRecommendationStrategy: boolean;
|
|
1337
1347
|
};
|
|
1338
1348
|
blocks: {
|
|
1339
1349
|
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")[];
|
|
@@ -1471,6 +1481,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1471
1481
|
modulesDisabled: boolean;
|
|
1472
1482
|
liquidSyntax: boolean;
|
|
1473
1483
|
autosave: boolean;
|
|
1484
|
+
reusableRecommendationStrategy: boolean;
|
|
1474
1485
|
};
|
|
1475
1486
|
blocks: {
|
|
1476
1487
|
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")[];
|
|
@@ -1608,6 +1619,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1608
1619
|
modulesDisabled: boolean;
|
|
1609
1620
|
liquidSyntax: boolean;
|
|
1610
1621
|
autosave: boolean;
|
|
1622
|
+
reusableRecommendationStrategy: boolean;
|
|
1611
1623
|
};
|
|
1612
1624
|
blocks: {
|
|
1613
1625
|
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")[];
|
|
@@ -1745,6 +1757,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1745
1757
|
modulesDisabled: boolean;
|
|
1746
1758
|
liquidSyntax: boolean;
|
|
1747
1759
|
autosave: boolean;
|
|
1760
|
+
reusableRecommendationStrategy: boolean;
|
|
1748
1761
|
};
|
|
1749
1762
|
blocks: {
|
|
1750
1763
|
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")[];
|
|
@@ -1882,6 +1895,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
1882
1895
|
modulesDisabled: boolean;
|
|
1883
1896
|
liquidSyntax: boolean;
|
|
1884
1897
|
autosave: boolean;
|
|
1898
|
+
reusableRecommendationStrategy: boolean;
|
|
1885
1899
|
};
|
|
1886
1900
|
blocks: {
|
|
1887
1901
|
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")[];
|
|
@@ -2019,6 +2033,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
2019
2033
|
modulesDisabled: boolean;
|
|
2020
2034
|
liquidSyntax: boolean;
|
|
2021
2035
|
autosave: boolean;
|
|
2036
|
+
reusableRecommendationStrategy: boolean;
|
|
2022
2037
|
};
|
|
2023
2038
|
blocks: {
|
|
2024
2039
|
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")[];
|
|
@@ -2156,6 +2171,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
2156
2171
|
modulesDisabled: boolean;
|
|
2157
2172
|
liquidSyntax: boolean;
|
|
2158
2173
|
autosave: boolean;
|
|
2174
|
+
reusableRecommendationStrategy: boolean;
|
|
2159
2175
|
};
|
|
2160
2176
|
blocks: {
|
|
2161
2177
|
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")[];
|
|
@@ -2293,6 +2309,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
2293
2309
|
modulesDisabled: boolean;
|
|
2294
2310
|
liquidSyntax: boolean;
|
|
2295
2311
|
autosave: boolean;
|
|
2312
|
+
reusableRecommendationStrategy: boolean;
|
|
2296
2313
|
};
|
|
2297
2314
|
blocks: {
|
|
2298
2315
|
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")[];
|
|
@@ -2430,6 +2447,7 @@ export declare const useConfigStore: import("pinia").StoreDefinition<"guido-conf
|
|
|
2430
2447
|
modulesDisabled: boolean;
|
|
2431
2448
|
liquidSyntax: boolean;
|
|
2432
2449
|
autosave: boolean;
|
|
2450
|
+
reusableRecommendationStrategy: boolean;
|
|
2433
2451
|
};
|
|
2434
2452
|
blocks: {
|
|
2435
2453
|
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")[];
|
|
@@ -25,3 +25,12 @@ export declare const getCsrfToken: () => string;
|
|
|
25
25
|
export declare const getUrlParams: () => URLSearchParams;
|
|
26
26
|
export declare const getUrlParam: (paramName: string, defaultValue?: string) => string;
|
|
27
27
|
export declare const replaceString: (string?: string, values?: Record<string, string | number>, isRemoveEmptyValues?: boolean) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Parses a JSON-string field, yielding `fallback` on absent or malformed input.
|
|
30
|
+
*
|
|
31
|
+
* Smart Recommender returns several strategy fields (`filters`, `base_product`, ...)
|
|
32
|
+
* as embedded JSON strings, and every surface that reads them must degrade to a
|
|
33
|
+
* sensible empty value rather than break. Shared so a hardening change (rejecting
|
|
34
|
+
* non-object payloads, logging a malformed blob) lands on all of them at once.
|
|
35
|
+
*/
|
|
36
|
+
export declare const parseJsonField: <T>(raw: string | undefined, fallback: T) => T;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL schemes that are safe to follow from partner-authored email HTML. Shared so a
|
|
3
|
+
* future bypass fix lands in one place — the preview guard and the recommendation
|
|
4
|
+
* sanitizer both gate on it. Stored with the trailing colon to match `anchor.protocol`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const BASE_SAFE_URL_SCHEMES: readonly string[];
|
|
@@ -3,8 +3,12 @@ const n = `.base-input {
|
|
|
3
3
|
border-radius: 4px;
|
|
4
4
|
background-color: var(--guido-color-gray-0);
|
|
5
5
|
align-items: center;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/* 40px is a floor, never a cap: \`.base-input\` is shared by every settings field,
|
|
7
|
+
including Stripo's own auto-height inputs (e.g. the link field) that expand on
|
|
8
|
+
focus. A fixed max-height clamped their inner box; keep 40px only as the floor. */
|
|
9
|
+
min-height: 40px;
|
|
10
|
+
height: auto;
|
|
11
|
+
max-height: none;
|
|
8
12
|
box-sizing: content-box;
|
|
9
13
|
outline: none;
|
|
10
14
|
resize: vertical;
|
|
@@ -36,11 +40,6 @@ ue-contenteditable .base-input {
|
|
|
36
40
|
line-height: 24px;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
/* Image link input is auto-height; lift the fixed 40px cap so it can grow. */
|
|
40
|
-
ue-contenteditable.link-autoheight-contenteditable .base-input {
|
|
41
|
-
max-height: none;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
43
|
ue-icon-component.icon-button.icon-clear-input {
|
|
45
44
|
right: 2px;
|
|
46
45
|
top: 2px;
|
package/dist/utils/dateUtil.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
import { DEFAULT_LOCALE as r, DEFAULT as
|
|
2
|
-
const
|
|
1
|
+
import { DEFAULT_LOCALE as r, DEFAULT as a, DEFAULT_TZ as c } from "../enums/date.js";
|
|
2
|
+
const m = (t) => t ? t instanceof Date ? t : typeof t == "string" ? t.length === 10 && /^\d{10}$/.test(t) ? new Date(Number(t) * 1e3) : new Date(t) : typeof t == "number" ? t.toString().length === 10 ? new Date(t * 1e3) : new Date(t) : /* @__PURE__ */ new Date() : /* @__PURE__ */ new Date(), s = () => {
|
|
3
3
|
const t = window.l10n;
|
|
4
|
-
return (t == null ? void 0 : t.locale) ===
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
return (t == null ? void 0 : t.locale) === a ? r : (t == null ? void 0 : t.locale) || r;
|
|
5
|
+
}, u = new Intl.DateTimeFormat().resolvedOptions().timeZone, f = () => {
|
|
6
|
+
const t = window.l10n;
|
|
7
|
+
return (t == null ? void 0 : t.timezone) || u || c;
|
|
8
|
+
}, D = (t, e = s(), n = f()) => {
|
|
9
|
+
const o = {
|
|
10
|
+
year: "numeric",
|
|
11
|
+
month: "2-digit",
|
|
12
|
+
day: "2-digit",
|
|
13
|
+
timeZone: n
|
|
14
|
+
}, i = m(t);
|
|
15
|
+
return new Intl.DateTimeFormat(e, o).format(i);
|
|
16
|
+
}, T = (t) => {
|
|
8
17
|
if (!t)
|
|
9
18
|
return "";
|
|
10
19
|
const e = new Date(t);
|
|
@@ -16,9 +25,13 @@ const i = (t) => {
|
|
|
16
25
|
second: "2-digit",
|
|
17
26
|
hour12: !1
|
|
18
27
|
}).format(e);
|
|
19
|
-
},
|
|
28
|
+
}, h = (t) => t ? Math.floor(Date.now() / 1e3) >= t : !1;
|
|
20
29
|
export {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
m as convertToDateObject,
|
|
31
|
+
T as formatPatchDate,
|
|
32
|
+
D as formatShortDate,
|
|
33
|
+
h as isAfterDate,
|
|
34
|
+
u as localTz,
|
|
35
|
+
s as locale,
|
|
36
|
+
f as timezone
|
|
24
37
|
};
|
|
@@ -58,11 +58,20 @@ const o = (l) => {
|
|
|
58
58
|
}, i = () => {
|
|
59
59
|
var l;
|
|
60
60
|
return ((l = document.head.querySelector('meta[name="csrf-token"]')) == null ? void 0 : l.getAttribute("content")) ?? "";
|
|
61
|
+
}, k = (l, s) => {
|
|
62
|
+
if (!l)
|
|
63
|
+
return s;
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(l);
|
|
66
|
+
} catch {
|
|
67
|
+
return s;
|
|
68
|
+
}
|
|
61
69
|
};
|
|
62
70
|
export {
|
|
63
71
|
v as buildMergeTagEntries,
|
|
64
72
|
f as dynamicContentToMergeTags,
|
|
65
73
|
b as flattenDynamicContentList,
|
|
66
74
|
i as getCsrfToken,
|
|
67
|
-
o as mergeTagToDynamicContent
|
|
75
|
+
o as mergeTagToDynamicContent,
|
|
76
|
+
k as parseJsonField
|
|
68
77
|
};
|