@useinsider/guido 3.2.0-beta.738ec8a → 3.2.0-beta.803b92e

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 (35) hide show
  1. package/README.md +25 -1
  2. package/dist/@types/config/schemas.js +38 -36
  3. package/dist/components/Guido.vue.js +4 -4
  4. package/dist/components/Guido.vue2.js +35 -34
  5. package/dist/components/organisms/AutoSaveController.vue.js +17 -0
  6. package/dist/components/organisms/AutoSaveController.vue2.js +13 -0
  7. package/dist/components/organisms/extensions/recommendation/FilterItem.vue.js +11 -9
  8. package/dist/components/organisms/extensions/recommendation/FilterItem.vue2.js +35 -70
  9. package/dist/components/organisms/header/AutoSaveToggle.vue.js +22 -0
  10. package/dist/components/organisms/header/AutoSaveToggle.vue2.js +19 -0
  11. package/dist/components/organisms/header/RightSlot.vue.js +8 -8
  12. package/dist/components/organisms/header/RightSlot.vue2.js +9 -8
  13. package/dist/composables/useAutoSave.js +68 -0
  14. package/dist/composables/useSave.js +15 -15
  15. package/dist/enums/extensions/recommendationBlock.js +27 -28
  16. package/dist/extensions/Blocks/Recommendation/utils/filterUtil.js +12 -25
  17. package/dist/guido.css +1 -1
  18. package/dist/src/@types/config/schemas.d.ts +4 -0
  19. package/dist/src/components/Guido.vue.d.ts +1 -1
  20. package/dist/src/components/organisms/AutoSaveController.vue.d.ts +2 -0
  21. package/dist/src/components/organisms/header/AutoSaveToggle.vue.d.ts +2 -0
  22. package/dist/src/components/organisms/header/EditorActions.vue.d.ts +1 -1
  23. package/dist/src/components/organisms/header/HeaderWrapper.vue.d.ts +1 -1
  24. package/dist/src/components/organisms/header/RightSlot.vue.d.ts +1 -1
  25. package/dist/src/composables/useAutoSave.d.ts +3 -0
  26. package/dist/src/composables/useConfig.d.ts +2 -0
  27. package/dist/src/composables/useSave.d.ts +1 -1
  28. package/dist/src/enums/extensions/recommendationBlock.d.ts +0 -1
  29. package/dist/src/extensions/Blocks/Recommendation/utils/filterUtil.d.ts +0 -2
  30. package/dist/src/stores/autosave.d.ts +6 -0
  31. package/dist/src/stores/config.d.ts +18 -0
  32. package/dist/src/utils/timeUtil.d.ts +8 -0
  33. package/dist/stores/autosave.js +11 -0
  34. package/dist/utils/timeUtil.js +19 -0
  35. package/package.json +1 -1
package/README.md CHANGED
@@ -143,7 +143,8 @@ const config: GuidoConfigInput = {
143
143
  displayConditions?: boolean, // Default: true
144
144
  unsubscribe?: boolean, // Default: true
145
145
  modulesDisabled?: boolean, // Default: false - Disable modules panel
146
- liquidSyntax?: boolean, // Default: false - Enable Liquid template syntax
146
+ liquidSyntax?: boolean, // Default: false - Enable Liquid template syntax
147
+ autosave?: boolean, // Default: false - Show the Auto Save toggle in the header. See wiki/AUTOSAVE.md.
147
148
  },
148
149
 
149
150
  // Optional: Callbacks
@@ -202,6 +203,7 @@ interface SavedTemplateDetails {
202
203
  config: number[];
203
204
  };
204
205
  metadata: Metadata;
206
+ silent: boolean; // true when triggered by autosave, false when user clicked Save
205
207
  }
206
208
 
207
209
  interface Metadata {
@@ -327,6 +329,28 @@ const config: GuidoConfigInput = {
327
329
 
328
330
  ---
329
331
 
332
+ ## Autosave
333
+
334
+ Guido ships an opt-in **autosave** that saves on a 3-minute interval and when the user leaves the tab. Enable it with the `features.autosave` feature flag — this **shows an "Auto Save" toggle in the editor header**; the end user switches autosave on per session.
335
+
336
+ ```typescript
337
+ const config: GuidoConfigInput = {
338
+ identity: { templateId: 'tpl-123', userId: 'user-456' },
339
+ partner: { name: 'partner' },
340
+ features: {
341
+ autosave: true, // Default: false — shows the Auto Save toggle in the header
342
+ },
343
+ };
344
+ ```
345
+
346
+ - Default is `false` — integrations see no change unless they opt in.
347
+ - Autosave reuses the same save pipeline as the Save button, so your existing `@save:complete` handler receives autosave output identically to a manual save. No new events or callbacks.
348
+ - Toggle state is **session-only** (Pinia) — resets to OFF on reload.
349
+
350
+ For a deep dive on triggers, guards, and limitations, see **[wiki/AUTOSAVE.md](wiki/AUTOSAVE.md)**.
351
+
352
+ ---
353
+
330
354
  ## HTML Compiler Rules
331
355
 
332
356
  Add custom rules to transform HTML during export:
@@ -1,5 +1,5 @@
1
1
  import { ModuleFolderDefaults as b } from "../../enums/defaults.js";
2
- import { object as o, number as p, optional as e, string as t, pipe as u, picklist as n, minLength as d, custom as S, boolean as a, array as c, literal as l, variant as k } from "../../node_modules/valibot/dist/index.js";
2
+ import { object as a, number as p, optional as e, string as t, pipe as u, picklist as n, minLength as d, custom as S, boolean as o, array as c, literal as l, variant as k } from "../../node_modules/valibot/dist/index.js";
3
3
  const m = {
4
4
  /** Promotional/marketing emails */
5
5
  PROMOTIONAL: 1,
@@ -12,7 +12,7 @@ const m = {
12
12
  ARCHITECT: 49,
13
13
  /** Unsubscribe page builder */
14
14
  UNSUBSCRIBE_PAGES: 97
15
- }, h = o({
15
+ }, h = a({
16
16
  /** Unique identifier for the template being edited */
17
17
  templateId: u(
18
18
  t(),
@@ -25,12 +25,12 @@ const m = {
25
25
  ),
26
26
  /** Optional variation ID for A/B testing */
27
27
  variationId: e(t())
28
- }), y = o({
28
+ }), f = a({
29
29
  /** Fallback font name (e.g., "Georgia") */
30
30
  name: t(),
31
31
  /** Fallback font family (e.g., "serif" or "sans-serif") */
32
32
  family: t()
33
- }), f = o({
33
+ }), y = a({
34
34
  /** Partner/organization name (required) */
35
35
  name: u(
36
36
  t(),
@@ -53,8 +53,8 @@ const m = {
53
53
  /** Display name for the current user */
54
54
  username: e(t(), "Guido User"),
55
55
  /** Fallback font settings from partner settings — used to match backend size calculation */
56
- fallbackFont: e(y)
57
- }), A = o({
56
+ fallbackFont: e(f)
57
+ }), A = a({
58
58
  /** Display text for the dynamic content */
59
59
  text: t(),
60
60
  /** Template variable value (e.g., {{username}}) */
@@ -63,12 +63,12 @@ const m = {
63
63
  fallback: e(t()),
64
64
  /** Optional formatting options */
65
65
  format: e(
66
- o({
66
+ a({
67
67
  key: t(),
68
68
  value: t()
69
69
  })
70
70
  )
71
- }), R = o({
71
+ }), R = a({
72
72
  /** Initial HTML content */
73
73
  html: e(t(), ""),
74
74
  /** Initial CSS content */
@@ -83,13 +83,13 @@ const m = {
83
83
  /** Selected unsubscribe page IDs */
84
84
  selectedUnsubscribePages: e(c(p()), []),
85
85
  /** Force recreate template in Stripo storage (use true when updating externally modified templates) */
86
- forceRecreate: e(a(), !1)
87
- }), C = o({
86
+ forceRecreate: e(o(), !1)
87
+ }), C = a({
88
88
  /** Sender display name */
89
89
  senderName: e(t(), ""),
90
90
  /** Email subject line */
91
91
  subject: e(t(), "")
92
- }), T = o({
92
+ }), T = a({
93
93
  /** Locale for the editor UI */
94
94
  locale: e(t(), "en"),
95
95
  /** Path to translations object */
@@ -102,28 +102,30 @@ const m = {
102
102
  savedModulesFolderName: e(t(), b.SAVED_MODULES),
103
103
  /** Folder name for default/prebuilt modules (used by Stripo plugin panel for path construction) */
104
104
  defaultModulesFolderName: e(t(), b.DEFAULT_MODULES)
105
- }), I = o({
105
+ }), I = a({
106
106
  /** Whether to show the header bar */
107
- showHeader: e(a(), !0),
107
+ showHeader: e(o(), !0),
108
108
  /** Custom label for back button (if shown) */
109
109
  backButtonLabel: e(t())
110
- }), E = o({
110
+ }), E = a({
111
111
  /** Enable dynamic content insertion */
112
- dynamicContent: e(a(), !0),
112
+ dynamicContent: e(o(), !0),
113
113
  /** Enable save as template functionality */
114
- saveAsTemplate: e(a(), !0),
114
+ saveAsTemplate: e(o(), !0),
115
115
  /** Enable version history */
116
- versionHistory: e(a(), !0),
116
+ versionHistory: e(o(), !0),
117
117
  /** Enable test message sending */
118
- testMessage: e(a(), !0),
118
+ testMessage: e(o(), !0),
119
119
  /** Enable display conditions */
120
- displayConditions: e(a(), !0),
120
+ displayConditions: e(o(), !0),
121
121
  /** Enable unsubscribe block */
122
- unsubscribe: e(a(), !0),
122
+ unsubscribe: e(o(), !0),
123
123
  /** Disable modules panel in the editor */
124
- modulesDisabled: e(a(), !1),
124
+ modulesDisabled: e(o(), !1),
125
125
  /** Enable Liquid template syntax */
126
- liquidSyntax: e(a(), !1)
126
+ liquidSyntax: e(o(), !1),
127
+ /** Enable autosave (3-min interval + tab-hide). User toggles on/off from the header. */
128
+ autosave: e(o(), !1)
127
129
  }), g = n([
128
130
  "amp-accordion",
129
131
  "amp-carousel",
@@ -146,7 +148,7 @@ const m = {
146
148
  "unsubscribe-block",
147
149
  "coupon-block",
148
150
  "items-block"
149
- ]), L = o({
151
+ ]), L = a({
150
152
  /** Default blocks to exclude from the editor */
151
153
  excludeDefaults: e(
152
154
  c(g),
@@ -157,14 +159,14 @@ const m = {
157
159
  c(O),
158
160
  []
159
161
  )
160
- }), r = o({
162
+ }), r = a({
161
163
  /** Unique identifier for the rule */
162
164
  id: t(),
163
165
  /** Human-readable description */
164
166
  description: e(t()),
165
167
  /** Priority for rule ordering (lower = earlier) */
166
168
  priority: p()
167
- }), M = o({
169
+ }), M = a({
168
170
  ...r.entries,
169
171
  type: l("replace"),
170
172
  /** String to search for */
@@ -172,8 +174,8 @@ const m = {
172
174
  /** Replacement string */
173
175
  replacement: t(),
174
176
  /** Replace all occurrences (default: false) */
175
- replaceAll: e(a())
176
- }), N = o({
177
+ replaceAll: e(o())
178
+ }), N = a({
177
179
  ...r.entries,
178
180
  type: l("regex"),
179
181
  /** Regex pattern string */
@@ -182,12 +184,12 @@ const m = {
182
184
  replacement: t(),
183
185
  /** Regex flags (e.g., 'gi') */
184
186
  flags: e(t())
185
- }), D = o({
187
+ }), D = a({
186
188
  ...r.entries,
187
189
  type: l("remove"),
188
190
  /** Strings or patterns to remove */
189
191
  targets: c(t())
190
- }), v = o({
192
+ }), v = a({
191
193
  ...r.entries,
192
194
  type: l("custom"),
193
195
  /** Custom processor function */
@@ -200,12 +202,12 @@ const m = {
200
202
  N,
201
203
  D,
202
204
  v
203
- ]), U = o({
205
+ ]), U = a({
204
206
  /** Custom compiler rules to apply */
205
207
  customRules: e(c(x), []),
206
208
  /** Skip default compiler rules */
207
- ignoreDefaultRules: e(a(), !1)
208
- }), B = o({
209
+ ignoreDefaultRules: e(o(), !1)
210
+ }), B = a({
209
211
  /**
210
212
  * External validation handler called before save completes.
211
213
  * Return false to cancel the save operation.
@@ -216,12 +218,12 @@ const m = {
216
218
  "externalValidation must be a function"
217
219
  )
218
220
  )
219
- }), H = o({
221
+ }), H = a({
220
222
  // Required sections
221
223
  /** Identity configuration (required) */
222
224
  identity: h,
223
225
  /** Partner configuration (required) */
224
- partner: f,
226
+ partner: y,
225
227
  // Optional sections (with defaults)
226
228
  /** Template content and presets */
227
229
  template: e(R, {}),
@@ -249,12 +251,12 @@ export {
249
251
  A as DynamicContentSchema,
250
252
  T as EditorSchema,
251
253
  C as EmailHeaderSchema,
252
- y as FallbackFontSchema,
254
+ f as FallbackFontSchema,
253
255
  E as FeaturesSchema,
254
256
  H as GuidoConfigSchema,
255
257
  h as IdentitySchema,
256
258
  m as MessageType,
257
- f as PartnerSchema,
259
+ y as PartnerSchema,
258
260
  s as ProductType,
259
261
  N as RegexRuleSchema,
260
262
  D as RemoveRuleSchema,
@@ -3,7 +3,7 @@ import i from "./Guido.vue2.js";
3
3
  import a from "../_virtual/_plugin-vue2_normalizer.js";
4
4
  var t = function() {
5
5
  var o = this, r = o._self._c, e = o._self._setupProxy;
6
- return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper, { ref: "headerWrapperRef" }), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : o._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.FilterSelectionDrawer), r(e.SaveAsTemplateDrawer), e.isTestPartner() ? o._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(p) {
6
+ return r("div", { ref: "wrapperRef", staticClass: "guido-editor__wrapper", class: { "guido-editor__no-header": e.noHeader } }, [r(e.HeaderWrapper, { ref: "headerWrapperRef" }), r(e.AutoSaveController), e.editorStore.isPreviewModeOpen ? r(e.PreviewContainer) : o._e(), r("div", { directives: [{ name: "show", rawName: "v-show", value: !e.previewStore.isLoaded, expression: "!previewStore.isLoaded" }], staticClass: "guido-editor__container", class: { "guido-editor__no-header": e.noHeader }, attrs: { id: "guido-editor" } }), r(e.Toaster), r(e.FilterSelectionDrawer), r(e.SaveAsTemplateDrawer), e.isTestPartner() ? o._e() : r(e.OnboardingWrapper, { on: { "onboarding-finished": function(p) {
7
7
  return e.emit("onboarding:finished");
8
8
  } } }), r(e.UnsubscribeWrapper), r(e.LoadingWrapper)], 1);
9
9
  }, n = [], s = /* @__PURE__ */ a(
@@ -12,9 +12,9 @@ var t = function() {
12
12
  n,
13
13
  !1,
14
14
  null,
15
- "25780af6"
15
+ "fffc13d6"
16
16
  );
17
- const u = s.exports;
17
+ const l = s.exports;
18
18
  export {
19
- u as default
19
+ l as default
20
20
  };
@@ -1,4 +1,4 @@
1
- import { defineComponent as j, defineAsyncComponent as R, ref as A, computed as I, watch as J, onMounted as Q, onUnmounted as X } from "vue";
1
+ import { defineComponent as j, defineAsyncComponent as N, ref as R, computed as I, watch as J, onMounted as Q, onUnmounted as X } from "vue";
2
2
  import { provideGuidoActions as Y } from "../composables/useGuidoActions.js";
3
3
  import { usePartner as Z } from "../composables/usePartner.js";
4
4
  import { useStripo as ee } from "../composables/useStripo.js";
@@ -6,42 +6,43 @@ import { useTimerClone as te } from "../composables/useTimerClone.js";
6
6
  import { migrate as W } from "../config/migrator/index.js";
7
7
  import { ModuleFolderDefaults as B } from "../enums/defaults.js";
8
8
  import { RIBBON_SELECTOR as oe } from "../enums/onboarding.js";
9
- import ne from "./organisms/base/Toaster.vue.js";
9
+ import ne from "./organisms/AutoSaveController.vue.js";
10
+ import re from "./organisms/base/Toaster.vue.js";
10
11
  import se from "./organisms/extensions/recommendation/FilterSelectionDrawer.vue.js";
11
- import re from "./organisms/header/HeaderWrapper.vue.js";
12
- import ce from "./organisms/LoadingWrapper.vue.js";
13
- import ae from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
14
- import ie from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
15
- import { useStripoApi as me } from "../services/stripoApi.js";
16
- import { useConfigStore as de } from "../stores/config.js";
17
- import { useDynamicContentStore as le } from "../stores/dynamic-content.js";
18
- import { useEditorStore as ue } from "../stores/editor.js";
19
- import { usePreviewStore as pe } from "../stores/preview.js";
20
- import { useUnsubscribeStore as fe } from "../stores/unsubscribe.js";
21
- const Re = /* @__PURE__ */ j({
12
+ import ce from "./organisms/header/HeaderWrapper.vue.js";
13
+ import ae from "./organisms/LoadingWrapper.vue.js";
14
+ import ie from "./organisms/save-as-template/SaveAsTemplateDrawer.vue.js";
15
+ import me from "./organisms/unsubscribe/UnsubscribeWrapper.vue.js";
16
+ import { useStripoApi as de } from "../services/stripoApi.js";
17
+ import { useConfigStore as le } from "../stores/config.js";
18
+ import { useDynamicContentStore as ue } from "../stores/dynamic-content.js";
19
+ import { useEditorStore as pe } from "../stores/editor.js";
20
+ import { usePreviewStore as fe } from "../stores/preview.js";
21
+ import { useUnsubscribeStore as ve } from "../stores/unsubscribe.js";
22
+ const Ie = /* @__PURE__ */ j({
22
23
  __name: "Guido",
23
24
  props: {
24
25
  config: null
25
26
  },
26
27
  emits: ["dynamic-content:open", "back", "save:start", "save:complete", "on-change", "ready", "onboarding:finished", "test-email:click"],
27
- setup(H, { expose: x, emit: s }) {
28
- const b = H, G = R(
28
+ setup(H, { expose: x, emit: r }) {
29
+ const S = H, G = N(
29
30
  () => import("./organisms/email-preview/PreviewContainer.vue.js")
30
- ), z = R(
31
+ ), z = N(
31
32
  () => import("./organisms/onboarding/OnboardingWrapper.vue.js")
32
- ), S = A(), d = A(), l = le(), g = fe(), a = de();
33
- a.init(b.config);
34
- const u = ue(), q = pe(), i = I(() => u.hasChanges), { isTestPartner: K } = Z(), w = () => {
33
+ ), b = R(), d = R(), l = ue(), g = ve(), a = le();
34
+ a.init(S.config);
35
+ const u = pe(), q = fe(), i = I(() => u.hasChanges), { isTestPartner: K } = Z(), w = () => {
35
36
  var e;
36
- return (e = S.value) == null ? void 0 : e.handleSave(!0);
37
+ return (e = b.value) == null ? void 0 : e.handleSave(!0);
37
38
  }, {
38
39
  templateId: p,
39
40
  userId: E,
40
41
  partnerName: D,
41
42
  username: C,
42
43
  template: t,
43
- editor: r
44
- } = a, m = (t == null ? void 0 : t.html) || "", T = (t == null ? void 0 : t.css) || "", f = (t == null ? void 0 : t.preselectedDynamicContent) || [], k = (r == null ? void 0 : r.savedModulesFolderName) || B.SAVED_MODULES, F = (r == null ? void 0 : r.defaultModulesFolderName) || B.DEFAULT_MODULES;
44
+ editor: s
45
+ } = a, m = (t == null ? void 0 : t.html) || "", T = (t == null ? void 0 : t.css) || "", f = (t == null ? void 0 : t.preselectedDynamicContent) || [], k = (s == null ? void 0 : s.savedModulesFolderName) || B.SAVED_MODULES, F = (s == null ? void 0 : s.defaultModulesFolderName) || B.DEFAULT_MODULES;
45
46
  u.templateId = p;
46
47
  const v = {
47
48
  emailId: p,
@@ -53,38 +54,38 @@ const Re = /* @__PURE__ */ j({
53
54
  }, L = {
54
55
  preselectedDynamicContentList: f,
55
56
  onReady: () => {
56
- console.debug("guido:ready"), s("ready");
57
+ console.debug("guido:ready"), r("ready");
57
58
  }
58
- }, { initPlugin: U } = ee(v, L), { getDefaultTemplate: _ } = me(), { cloneTimersOnSave: M, hasTimerBlocks: O } = te(), V = I(() => {
59
+ }, { initPlugin: U } = ee(v, L), { getDefaultTemplate: _ } = de(), { cloneTimersOnSave: M, hasTimerBlocks: O } = te(), V = I(() => {
59
60
  var e;
60
61
  return !((e = a.ui) != null && e.showHeader);
61
62
  });
62
63
  Y({
63
64
  onBack: () => {
64
- console.debug("guido:back"), s("back");
65
+ console.debug("guido:back"), r("back");
65
66
  },
66
67
  onSaveStart: () => {
67
- console.debug("guido:save:start"), s("save:start");
68
+ console.debug("guido:save:start"), r("save:start");
68
69
  },
69
70
  onSaveComplete: (e) => {
70
71
  const n = { ...e, metadata: v };
71
- console.debug("guido:save:complete", n), s("save:complete", n);
72
+ console.debug("guido:save:complete", n), r("save:complete", n);
72
73
  },
73
74
  onTestEmailClick: () => {
74
- console.debug("guido:test-email:click"), s("test-email:click");
75
+ console.debug("guido:test-email:click"), r("test-email:click");
75
76
  }
76
77
  });
77
78
  const P = (e) => {
78
79
  console.debug("dynamic-content:close", e), l.setSelectedDynamicContent(e), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: e }));
79
- }, N = () => {
80
+ }, A = () => {
80
81
  console.debug("dynamic-content:close", "Without Data"), document.dispatchEvent(new CustomEvent("dynamic-content:close", { detail: { text: "", value: "" } }));
81
82
  };
82
83
  J(() => i.value, () => {
83
- s("on-change", i.value);
84
+ r("on-change", i.value);
84
85
  });
85
86
  const y = (e) => {
86
87
  const n = e, { attribute: o, position: $ } = n.detail;
87
- console.debug("dynamic-content:open", n.detail), s("dynamic-content:open", o, $);
88
+ console.debug("dynamic-content:open", n.detail), r("dynamic-content:open", o, $);
88
89
  };
89
90
  let c = null;
90
91
  const h = () => {
@@ -119,13 +120,13 @@ const Re = /* @__PURE__ */ j({
119
120
  }), x({
120
121
  dynamicContent: {
121
122
  insert: P,
122
- close: N
123
+ close: A
123
124
  },
124
125
  hasChanges: i,
125
126
  saveSilent: w
126
- }), { __sfc: !0, PreviewContainer: G, OnboardingWrapper: z, headerWrapperRef: S, wrapperRef: d, dynamicContentStore: l, unsubscribeStore: g, props: b, configStore: a, editorStore: u, previewStore: q, hasChanges: i, isTestPartner: K, saveSilent: w, templateId: p, userId: E, partnerName: D, username: C, templateConfig: t, editorConfig: r, html: m, css: T, preselectedDynamicContentList: f, savedModulesFolderName: k, defaultModulesFolderName: F, emit: s, metadata: v, options: L, initPlugin: U, getDefaultTemplate: _, cloneTimersOnSave: M, hasTimerBlocks: O, noHeader: V, insertDynamicContent: P, closeDynamicContent: N, handleDynamicContentOpen: y, ribbonObserver: c, updateRibbonOffset: h, Toaster: ne, FilterSelectionDrawer: se, HeaderWrapper: re, LoadingWrapper: ce, SaveAsTemplateDrawer: ae, UnsubscribeWrapper: ie };
127
+ }), { __sfc: !0, PreviewContainer: G, OnboardingWrapper: z, headerWrapperRef: b, wrapperRef: d, dynamicContentStore: l, unsubscribeStore: g, props: S, configStore: a, editorStore: u, previewStore: q, hasChanges: i, isTestPartner: K, saveSilent: w, templateId: p, userId: E, partnerName: D, username: C, templateConfig: t, editorConfig: s, html: m, css: T, preselectedDynamicContentList: f, savedModulesFolderName: k, defaultModulesFolderName: F, emit: r, metadata: v, options: L, initPlugin: U, getDefaultTemplate: _, cloneTimersOnSave: M, hasTimerBlocks: O, noHeader: V, insertDynamicContent: P, closeDynamicContent: A, handleDynamicContentOpen: y, ribbonObserver: c, updateRibbonOffset: h, AutoSaveController: ne, Toaster: re, FilterSelectionDrawer: se, HeaderWrapper: ce, LoadingWrapper: ae, SaveAsTemplateDrawer: ie, UnsubscribeWrapper: me };
127
128
  }
128
129
  });
129
130
  export {
130
- Re as default
131
+ Ie as default
131
132
  };
@@ -0,0 +1,17 @@
1
+ import n from "./AutoSaveController.vue2.js";
2
+ import t from "../../_virtual/_plugin-vue2_normalizer.js";
3
+ var o = function() {
4
+ var r = this, e = r._self._c;
5
+ return r._self._setupProxy, e("div", { staticClass: "d-n" });
6
+ }, s = [], _ = /* @__PURE__ */ t(
7
+ n,
8
+ o,
9
+ s,
10
+ !1,
11
+ null,
12
+ null
13
+ );
14
+ const f = _.exports;
15
+ export {
16
+ f as default
17
+ };
@@ -0,0 +1,13 @@
1
+ import { defineComponent as t } from "vue";
2
+ import { useAutoSave as r } from "../../composables/useAutoSave.js";
3
+ import { useSave as s } from "../../composables/useSave.js";
4
+ const f = /* @__PURE__ */ t({
5
+ __name: "AutoSaveController",
6
+ setup(a) {
7
+ const { save: e } = s(), o = () => e(!1, !0);
8
+ return r(o), { __sfc: !0, save: e, backgroundSave: o };
9
+ }
10
+ });
11
+ export {
12
+ f as default
13
+ };
@@ -1,24 +1,26 @@
1
- import l from "./FilterItem.vue2.js";
1
+ import r from "./FilterItem.vue2.js";
2
2
  /* empty css */
3
- import i from "../../../../_virtual/_plugin-vue2_normalizer.js";
4
- var r = function() {
3
+ import l from "../../../../_virtual/_plugin-vue2_normalizer.js";
4
+ var i = function() {
5
5
  var a = this, e = a._self._c, t = a._self._setupProxy;
6
6
  return e("div", { staticClass: "d-f f-d-c w-1 gap-16", attrs: { "data-filter-group": a.filter.filterGroup, "data-filter-number": a.filter.filterNumber } }, [e("div", { staticClass: "d-f a-i-c j-c-s-b pt-4", class: { "bor-t-s-s bor-t-w-1 bor-t-c-50": a.index === 0 } }, [e("p", [a._v(" " + a._s(t.trans("newsletter.filter")) + " " + a._s(a.index + 1) + " ")]), e(t.InButtonV2, { attrs: { id: "guido__delete-filter-group-button", "left-icon": "line-delete", styling: "text", type: "danger", "label-text-status": !1 }, on: { click: function(s) {
7
7
  return t.emit("delete-filter", t.props.filter);
8
- } } })], 1), e("div", { staticClass: "w-1 d-f a-i-s j-c-s-b gap-16" }, [e(t.InSelect, { staticClass: "w-2", attrs: { "disabled-status": "", "search-status": "", "button-status": !1, "label-text": t.trans("action-builder.filter-type"), options: t.filterTypeOptions, value: [t.filterTypeOptions[0]] } }), e(t.InSelect, { staticClass: "w-2", attrs: { id: "filter-item-input--attribute-type", "search-status": "", "static-position": "bottom right", "button-status": !1, "label-text": t.trans("condition.attribute"), options: t.store.getFilterList, state: t.getFieldState("attribute"), value: [t.selectedAttributeType] }, on: { select: t.handleAttributeChange } })], 1), e("div", { staticClass: "w-1 d-f a-i-s j-c-s-b gap-16" }, [t.isBooleanAttribute ? e(t.InSelect, { staticClass: "w-2", attrs: { "button-status": !1, "label-text": t.trans("condition.operator"), options: t.booleanValueOptions, state: t.getFieldState("value"), value: [t.selectedBooleanValue] }, on: { select: t.handleBooleanValueChange } }) : [e(t.InSelect, { staticClass: "w-2", attrs: { "button-status": !1, "label-text": t.trans("condition.operator"), options: t.getOperatorOptions(t.selectedAttributeType.type), state: t.getFieldState("operator"), value: [t.selectedOperatorType] }, on: { select: t.handleOperatorChange } }), t.isAnyOfOperator ? e(t.InTags, { staticClass: "w-2", attrs: { "allow-bulk-paste": "", validate: "text", "allow-duplicates": !1, invalid: t.invalidFields.has("value"), "invalid-message": t.valueErrorMessage, label: t.trans("condition.value"), placeholder: t.trans("condition.enter-value-placeholder"), value: t.tagValues }, on: { input: t.onTagsInput } }) : t.isDateAttribute ? e(t.InDatePickerV2, { staticClass: "w-2", attrs: { id: `filter-item-input--value-${a.index}`, "single-date-picker-status": "", "label-text": t.trans("condition.value"), locale: t.datePickerLocale, name: `filter-item-input--value-${a.index}`, "placeholder-text": t.trans("condition.enter-value-placeholder"), state: t.getFieldState("value"), "state-message": t.valueErrorMessage, value: t.datePickerValue }, on: { apply: t.onDatePickerApply } }) : e(t.InBasicTextInput, { staticClass: "w-2", attrs: { id: `filter-item-input--value-${a.index}`, name: "imageUrl", "character-counter-status": !1, "label-text": t.trans("condition.value"), "max-character-length": 25, "placeholder-text": t.trans("condition.enter-value-placeholder"), "state-message": t.valueErrorMessage, states: t.getFieldState("value"), "tooltip-status": !1, type: t.valueInputType, value: t.safeDecodeURIComponent(t.props.filter.value) }, on: { input: function(s) {
8
+ } } })], 1), e("div", { staticClass: "w-1 d-f a-i-s j-c-s-b gap-16" }, [e(t.InSelect, { staticClass: "w-2", attrs: { "disabled-status": "", "search-status": "", "button-status": !1, "label-text": t.trans("action-builder.filter-type"), options: t.filterTypeOptions, value: [t.filterTypeOptions[0]] } }), e(t.InSelect, { staticClass: "w-2", attrs: { id: "filter-item-input--attribute-type", "search-status": "", "static-position": "bottom right", "button-status": !1, "label-text": t.trans("condition.attribute"), options: t.store.getFilterList, state: t.getFieldState("attribute"), value: [t.selectedAttributeType] }, on: { select: t.handleAttributeChange } })], 1), e("div", { staticClass: "w-1 d-f a-i-s j-c-s-b gap-16" }, [t.isBooleanAttribute ? e(t.InSelect, { staticClass: "w-2", attrs: { "button-status": !1, "label-text": t.trans("condition.operator"), options: t.booleanValueOptions, state: t.getFieldState("value"), value: [t.selectedBooleanValue] }, on: { select: t.handleBooleanValueChange } }) : [e(t.InSelect, { staticClass: "w-2", attrs: { "button-status": !1, "label-text": t.trans("condition.operator"), options: t.getOperatorOptions(t.selectedAttributeType.type), state: t.getFieldState("operator"), value: [t.selectedOperatorType] }, on: { select: function(s) {
9
+ return t.updateFilter({ text: "operator", value: s.value });
10
+ } } }), e(t.InBasicTextInput, { staticClass: "w-2", attrs: { id: "filter-item-input--value", name: "imageUrl", "character-counter-status": !1, "label-text": t.trans("condition.value"), "max-character-length": 25, "placeholder-text": t.trans("condition.enter-value-placeholder"), "state-message": t.valueErrorMessage, states: t.getFieldState("value"), "tooltip-status": !1, type: t.valueInputType, value: decodeURIComponent(t.props.filter.value) }, on: { input: function(s) {
9
11
  t.updateFilter({ text: "value", value: encodeURIComponent(s) });
10
12
  } } })]], 2), t.props.hasLogicAdapter ? e("div", { staticClass: "w-1 d-f a-i-c j-c-c p-r bor-b-s-s bor-b-w-1 bor-b-c-50 mt-4" }, [e(t.LogicAdapter, { staticClass: "p-a", attrs: { logic: t.props.filter.innerGroupOperator }, on: { change: function(s) {
11
13
  return t.updateFilter({ text: "innerGroupOperator", value: s });
12
14
  } } })], 1) : a._e()]);
13
- }, n = [], o = /* @__PURE__ */ i(
14
- l,
15
+ }, o = [], n = /* @__PURE__ */ l(
15
16
  r,
16
- n,
17
+ i,
18
+ o,
17
19
  !1,
18
20
  null,
19
- "8053a037"
21
+ "3b53a736"
20
22
  );
21
- const f = o.exports;
23
+ const f = n.exports;
22
24
  export {
23
25
  f as default
24
26
  };
@@ -1,14 +1,12 @@
1
- import { defineComponent as N, computed as r } from "vue";
2
- import { useTranslations as U } from "../../../../composables/useTranslations.js";
3
- import { getOperatorOptions as f, OP_ANY_OF as d } from "../../../../enums/extensions/recommendationBlock.js";
4
- import { useRecommendationExtensionStore as E } from "../../../../extensions/Blocks/Recommendation/store/recommendation.js";
5
- import { parseTagList as j, safeDecodeURIComponent as g } from "../../../../extensions/Blocks/Recommendation/utils/filterUtil.js";
6
- import { getInvalidFilterFields as w } from "../../../../extensions/Blocks/Recommendation/validation/filterSchema.js";
7
- import { locale as M } from "../../../../utils/dateUtil.js";
8
- import { InTags as Y, InButtonV2 as q, InSelect as z, InDatePickerV2 as G, InBasicTextInput as H } from "@useinsider/design-system-vue";
9
- import J from "./LogicAdapter.vue.js";
10
- import { useDebounceFn as K } from "../../../../node_modules/@vueuse/shared/index.js";
11
- const se = /* @__PURE__ */ N({
1
+ import { defineComponent as _, computed as l } from "vue";
2
+ import { useTranslations as C } from "../../../../composables/useTranslations.js";
3
+ import { getOperatorOptions as p } from "../../../../enums/extensions/recommendationBlock.js";
4
+ import { useRecommendationExtensionStore as V } from "../../../../extensions/Blocks/Recommendation/store/recommendation.js";
5
+ import { getInvalidFilterFields as A } from "../../../../extensions/Blocks/Recommendation/validation/filterSchema.js";
6
+ import { InButtonV2 as L, InSelect as O, InBasicTextInput as S } from "@useinsider/design-system-vue";
7
+ import E from "./LogicAdapter.vue.js";
8
+ import { useDebounceFn as N } from "../../../../node_modules/@vueuse/shared/index.js";
9
+ const K = /* @__PURE__ */ _({
12
10
  __name: "FilterItem",
13
11
  props: {
14
12
  filter: null,
@@ -17,88 +15,55 @@ const se = /* @__PURE__ */ N({
17
15
  submitted: { type: Boolean }
18
16
  },
19
17
  emits: ["delete-filter"],
20
- setup(I, { emit: O }) {
21
- const t = I, s = U(), n = E(), T = [
18
+ setup(f, { emit: v }) {
19
+ const t = f, n = C(), a = V(), y = [
22
20
  {
23
- text: s("email-editor.standard-filter"),
21
+ text: n("email-editor.standard-filter"),
24
22
  value: "standardFilter"
25
23
  }
26
- ], u = [
24
+ ], i = [
27
25
  { text: "True", value: "true" },
28
26
  { text: "False", value: "false" }
29
- ], m = r(() => t.filter.attribute || ""), i = r(() => n.getFilterList.find((e) => e.value === m.value) || { text: "", value: "", type: "" }), h = r(
27
+ ], d = l(() => t.filter.attribute || ""), r = l(() => a.getFilterList.find((e) => e.value === d.value) || { text: "", value: "", type: "" }), F = l(
30
28
  () => {
31
29
  var e;
32
- return ((e = i.value) == null ? void 0 : e.type) === "Boolean";
30
+ return ((e = r.value) == null ? void 0 : e.type) === "Boolean";
33
31
  }
34
- ), b = r(() => {
32
+ ), b = l(() => {
35
33
  var e;
36
- return f((e = i.value) == null ? void 0 : e.type).find((o) => o.value === t.filter.operator);
37
- }), A = r(
38
- () => u.find((e) => e.value === t.filter.value) || u[0]
39
- ), p = r(() => t.submitted ? w(t.filter) : /* @__PURE__ */ new Set()), x = (e) => p.value.has(e) ? "error" : "default", B = r(
40
- () => p.value.has("value") ? s("action-builder.filter-empty-value-error") : ""
41
- ), v = r(
34
+ return p((e = r.value) == null ? void 0 : e.type).find((o) => o.value === t.filter.operator);
35
+ }), g = l(
36
+ () => i.find((e) => e.value === t.filter.value) || i[0]
37
+ ), u = l(() => t.submitted ? A(t.filter) : /* @__PURE__ */ new Set()), h = (e) => u.value.has(e) ? "error" : "default", B = l(
38
+ () => u.value.has("value") ? n("action-builder.filter-empty-value-error") : ""
39
+ ), c = l(
42
40
  () => {
43
41
  var e;
44
- return ((e = i.value) == null ? void 0 : e.type) === "Number";
42
+ return ((e = r.value) == null ? void 0 : e.type) === "Number";
45
43
  }
46
- ), D = r(() => v.value ? "number" : "text"), C = r(
47
- () => {
48
- var e;
49
- return ((e = i.value) == null ? void 0 : e.type) === "Date";
50
- }
51
- ), _ = r(() => t.filter.operator === d), k = r(() => j(t.filter.value)), P = K((e) => {
52
- n.updateFilter({
44
+ ), x = l(() => c.value ? "number" : "text"), T = N((e) => {
45
+ a.updateFilter({
53
46
  ...t.filter,
54
47
  [e.text]: e.value
55
48
  });
56
- }, 500), V = (e) => {
57
- const o = n.getFilterList.find((c) => c.value === e.value), l = (o == null ? void 0 : o.type) === "Boolean", [a] = f(o == null ? void 0 : o.type);
58
- n.updateFilter({
49
+ }, 500);
50
+ return { __sfc: !0, trans: n, store: a, props: t, filterTypeOptions: y, booleanValueOptions: i, attributeType: d, selectedAttributeType: r, isBooleanAttribute: F, selectedOperatorType: b, selectedBooleanValue: g, emit: v, invalidFields: u, getFieldState: h, valueErrorMessage: B, isNumericAttribute: c, valueInputType: x, updateFilter: T, handleAttributeChange: (e) => {
51
+ const o = a.getFilterList.find((I) => I.value === e.value), m = (o == null ? void 0 : o.type) === "Boolean", [s] = p(o == null ? void 0 : o.type);
52
+ a.updateFilter({
59
53
  ...t.filter,
60
54
  attribute: e.value,
61
- operator: l ? "=" : (a == null ? void 0 : a.value) ?? "",
62
- value: l ? "true" : ""
55
+ operator: m ? "=" : (s == null ? void 0 : s.value) ?? "",
56
+ value: m ? "true" : ""
63
57
  });
64
- }, L = (e) => {
65
- n.updateFilter({
58
+ }, handleBooleanValueChange: (e) => {
59
+ a.updateFilter({
66
60
  ...t.filter,
67
61
  operator: "=",
68
62
  value: e.value
69
63
  });
70
- }, S = (e) => {
71
- const o = e.value;
72
- if (o === t.filter.operator)
73
- return;
74
- const c = t.filter.operator === d !== (o === d);
75
- n.updateFilter({
76
- ...t.filter,
77
- operator: o,
78
- value: c ? "" : t.filter.value
79
- });
80
- }, $ = M(), y = (e) => {
81
- const [o, l, a] = e.split("-");
82
- return !o || !l || !a ? "" : `${l}/${a}/${o}`;
83
- }, F = (e) => {
84
- const [o, l, a] = e.split("/");
85
- return !a || !o || !l ? "" : `${a}-${o.padStart(2, "0")}-${l.padStart(2, "0")}`;
86
- }, R = r(
87
- () => y(g(t.filter.value))
88
- );
89
- return { __sfc: !0, trans: s, store: n, props: t, filterTypeOptions: T, booleanValueOptions: u, attributeType: m, selectedAttributeType: i, isBooleanAttribute: h, selectedOperatorType: b, selectedBooleanValue: A, emit: O, invalidFields: p, getFieldState: x, valueErrorMessage: B, isNumericAttribute: v, valueInputType: D, isDateAttribute: C, isAnyOfOperator: _, tagValues: k, updateFilter: P, handleAttributeChange: V, handleBooleanValueChange: L, handleOperatorChange: S, datePickerLocale: $, isoToPickerDate: y, pickerDateToIso: F, datePickerValue: R, onDatePickerApply: (e) => {
90
- n.updateFilter({
91
- ...t.filter,
92
- value: encodeURIComponent(F(e))
93
- });
94
- }, onTagsInput: (e) => {
95
- n.updateFilter({
96
- ...t.filter,
97
- value: e.map(encodeURIComponent).join(",")
98
- });
99
- }, getOperatorOptions: f, safeDecodeURIComponent: g, InBasicTextInput: H, InDatePickerV2: G, InSelect: z, InButtonV2: q, InTags: Y, LogicAdapter: J };
64
+ }, getOperatorOptions: p, InBasicTextInput: S, InSelect: O, InButtonV2: L, LogicAdapter: E };
100
65
  }
101
66
  });
102
67
  export {
103
- se as default
68
+ K as default
104
69
  };