@antelopejs/dms-mailing 0.6.1 → 0.7.1

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 (236) hide show
  1. package/README.md +8 -7
  2. package/dist/constants.d.ts +1 -2
  3. package/dist/constants.js +2 -3
  4. package/dist/constants.js.map +1 -1
  5. package/dist/data/templates-table.d.ts +4 -1
  6. package/dist/data/templates-table.js +55 -20
  7. package/dist/data/templates-table.js.map +1 -1
  8. package/dist/data-types/categories-type.d.ts +5 -5
  9. package/dist/db/models/index.d.ts +0 -1
  10. package/dist/db/models/index.js +0 -1
  11. package/dist/db/models/index.js.map +1 -1
  12. package/dist/db/models/send-events.model.js +2 -3
  13. package/dist/db/models/send-events.model.js.map +1 -1
  14. package/dist/db/models/sends.model.js +2 -3
  15. package/dist/db/models/sends.model.js.map +1 -1
  16. package/dist/db/models/templates.model.d.ts +10 -1
  17. package/dist/db/models/templates.model.js +29 -10
  18. package/dist/db/models/templates.model.js.map +1 -1
  19. package/dist/db/tables/index.d.ts +0 -1
  20. package/dist/db/tables/index.js +0 -1
  21. package/dist/db/tables/index.js.map +1 -1
  22. package/dist/db/tables/settings.table.d.ts +0 -1
  23. package/dist/db/tables/settings.table.js +0 -4
  24. package/dist/db/tables/settings.table.js.map +1 -1
  25. package/dist/db/tables/templates.table.d.ts +7 -4
  26. package/dist/db/tables/templates.table.js +4 -14
  27. package/dist/db/tables/templates.table.js.map +1 -1
  28. package/dist/engine/formats.d.ts +13 -0
  29. package/dist/engine/formats.js +85 -0
  30. package/dist/engine/formats.js.map +1 -0
  31. package/dist/engine/index.d.ts +1 -0
  32. package/dist/engine/index.js +1 -0
  33. package/dist/engine/index.js.map +1 -1
  34. package/dist/engine/resolve.d.ts +2 -1
  35. package/dist/engine/resolve.js +14 -7
  36. package/dist/engine/resolve.js.map +1 -1
  37. package/dist/engine/tokens.d.ts +2 -1
  38. package/dist/engine/tokens.js +3 -5
  39. package/dist/engine/tokens.js.map +1 -1
  40. package/dist/frontend-module.d.ts +2 -0
  41. package/dist/frontend-module.js +24 -0
  42. package/dist/frontend-module.js.map +1 -0
  43. package/dist/hooks/index.d.ts +0 -1
  44. package/dist/hooks/index.js +0 -1
  45. package/dist/hooks/index.js.map +1 -1
  46. package/dist/hooks/tenant-export.js +4 -1
  47. package/dist/hooks/tenant-export.js.map +1 -1
  48. package/dist/implementations/dms-mailing/index.d.ts +3 -3
  49. package/dist/implementations/dms-mailing/index.js +8 -7
  50. package/dist/implementations/dms-mailing/index.js.map +1 -1
  51. package/dist/index.js +2 -20
  52. package/dist/index.js.map +1 -1
  53. package/dist/pages/overview.d.ts +1 -1
  54. package/dist/pages/overview.js +11 -13
  55. package/dist/pages/overview.js.map +1 -1
  56. package/dist/pages/sends.d.ts +1 -1
  57. package/dist/pages/sends.js +16 -8
  58. package/dist/pages/sends.js.map +1 -1
  59. package/dist/pages/settings/form.js +8 -0
  60. package/dist/pages/settings/form.js.map +1 -1
  61. package/dist/pages/templates.js +3 -8
  62. package/dist/pages/templates.js.map +1 -1
  63. package/dist/pages/toolbar.d.ts +12 -0
  64. package/dist/pages/toolbar.js +41 -0
  65. package/dist/pages/toolbar.js.map +1 -0
  66. package/dist/realtime.d.ts +2 -2
  67. package/dist/realtime.js +8 -8
  68. package/dist/realtime.js.map +1 -1
  69. package/dist/routes/metrics.d.ts +9 -2
  70. package/dist/routes/metrics.js +90 -35
  71. package/dist/routes/metrics.js.map +1 -1
  72. package/dist/routes/period.d.ts +1 -0
  73. package/dist/routes/period.js +19 -0
  74. package/dist/routes/period.js.map +1 -1
  75. package/dist/routes/sends.js +6 -3
  76. package/dist/routes/sends.js.map +1 -1
  77. package/dist/routes/settings.js +6 -7
  78. package/dist/routes/settings.js.map +1 -1
  79. package/dist/routes/templates.d.ts +8 -4
  80. package/dist/routes/templates.js +41 -20
  81. package/dist/routes/templates.js.map +1 -1
  82. package/dist/services/categories.d.ts +2 -1
  83. package/dist/services/categories.js +9 -0
  84. package/dist/services/categories.js.map +1 -1
  85. package/dist/services/declarations.js +42 -184
  86. package/dist/services/declarations.js.map +1 -1
  87. package/dist/services/events.js +1 -1
  88. package/dist/services/events.js.map +1 -1
  89. package/dist/services/localized-text.d.ts +7 -0
  90. package/dist/services/localized-text.js +28 -0
  91. package/dist/services/localized-text.js.map +1 -0
  92. package/dist/services/send-import.js +0 -2
  93. package/dist/services/send-import.js.map +1 -1
  94. package/dist/services/send-stat-items.js +34 -12
  95. package/dist/services/send-stat-items.js.map +1 -1
  96. package/dist/services/send-stats.d.ts +7 -0
  97. package/dist/services/send-stats.js +17 -5
  98. package/dist/services/send-stats.js.map +1 -1
  99. package/dist/services/send.d.ts +2 -0
  100. package/dist/services/send.js +11 -12
  101. package/dist/services/send.js.map +1 -1
  102. package/dist/services/sender-declaration.d.ts +2 -0
  103. package/dist/services/sender-declaration.js +18 -0
  104. package/dist/services/sender-declaration.js.map +1 -0
  105. package/dist/services/settings.d.ts +1 -1
  106. package/dist/services/settings.js +1 -5
  107. package/dist/services/settings.js.map +1 -1
  108. package/dist/services/starters.d.ts +2 -2
  109. package/dist/services/starters.js +1 -10
  110. package/dist/services/starters.js.map +1 -1
  111. package/dist/services/templates.d.ts +13 -7
  112. package/dist/services/templates.js +72 -33
  113. package/dist/services/templates.js.map +1 -1
  114. package/dist/services/webhook-status.d.ts +2 -1
  115. package/dist/services/webhook-status.js +6 -5
  116. package/dist/services/webhook-status.js.map +1 -1
  117. package/dist/types/settings.d.ts +8 -0
  118. package/dist/types/settings.js +33 -6
  119. package/dist/types/settings.js.map +1 -1
  120. package/dist/validation/declarations.schema.d.ts +25 -7
  121. package/dist/validation/declarations.schema.js +16 -3
  122. package/dist/validation/declarations.schema.js.map +1 -1
  123. package/dist/validation/settings.schema.d.ts +41 -41
  124. package/dist/validation/settings.schema.js +30 -6
  125. package/dist/validation/settings.schema.js.map +1 -1
  126. package/dist/validation/templates.schema.d.ts +13 -0
  127. package/dist/validation/templates.schema.js +6 -1
  128. package/dist/validation/templates.schema.js.map +1 -1
  129. package/frontend-vue/app/components/CategoriesInput.vue +15 -13
  130. package/frontend-vue/app/components/FunnelCard.vue +46 -3
  131. package/frontend-vue/app/components/NewTemplateModal.vue +4 -2
  132. package/frontend-vue/app/components/OverviewGate.vue +0 -8
  133. package/frontend-vue/app/components/ProviderPill.vue +50 -0
  134. package/frontend-vue/app/components/SendDrawer.vue +206 -183
  135. package/frontend-vue/app/components/StarterGallery.vue +1 -1
  136. package/frontend-vue/app/components/TemplateCard.vue +4 -1
  137. package/frontend-vue/app/components/TemplateDrawer.vue +3 -5
  138. package/frontend-vue/app/components/TemplateGallery.vue +57 -17
  139. package/frontend-vue/app/components/TemplatePreviewFrame.vue +41 -11
  140. package/frontend-vue/app/components/editor/EditorTemplatePane.vue +1 -3
  141. package/frontend-vue/app/components/editor/EditorTitle.vue +1 -7
  142. package/frontend-vue/app/composables/useLocalizedDefaults.ts +5 -7
  143. package/frontend-vue/app/composables/useMailingApi.ts +3 -3
  144. package/frontend-vue/app/composables/useMailingReads.ts +2 -2
  145. package/frontend-vue/app/composables/useTemplateCategories.ts +8 -7
  146. package/frontend-vue/app/types/mailing.ts +18 -0
  147. package/frontend-vue/app/utils/categories.ts +58 -49
  148. package/frontend-vue/app/utils/funnel.ts +25 -0
  149. package/frontend-vue/app/utils/period.ts +0 -7
  150. package/frontend-vue/app/utils/starters.ts +3 -1
  151. package/frontend-vue/app/utils/tokens.ts +6 -1
  152. package/frontend-vue/i18n/locales/mailing-en-GB.json +19 -28
  153. package/frontend-vue/i18n/locales/mailing-fr-FR.json +19 -28
  154. package/frontend-vue/package.json +1 -1
  155. package/frontend-vue/tests/categories-input.test.ts +4 -10
  156. package/frontend-vue/tests/categories.test.ts +55 -17
  157. package/frontend-vue/tests/conditions.test.ts +1 -4
  158. package/frontend-vue/tests/funnel-card.test.ts +27 -0
  159. package/frontend-vue/tests/funnel.test.ts +25 -0
  160. package/frontend-vue/tests/localized-defaults.test.ts +0 -29
  161. package/frontend-vue/tests/new-template-modal.test.ts +1 -1
  162. package/frontend-vue/tests/overview-gate.test.ts +1 -24
  163. package/frontend-vue/tests/page-reads.test.ts +9 -25
  164. package/frontend-vue/tests/period.test.ts +0 -12
  165. package/frontend-vue/tests/replay-toast.test.ts +2 -1
  166. package/frontend-vue/tests/send-drawer.test.ts +123 -0
  167. package/frontend-vue/tests/template-drawer.test.ts +1 -1
  168. package/frontend-vue/tests/template-gallery.test.ts +90 -3
  169. package/frontend-vue/tests/template-preview-frame.test.ts +92 -0
  170. package/package.json +8 -7
  171. package/skills/dms-mailing/SKILL.md +25 -18
  172. package/src/constants.ts +2 -2
  173. package/src/data/sends-table.ts +1 -1
  174. package/src/data/templates-table.ts +125 -33
  175. package/src/db/models/index.ts +0 -1
  176. package/src/db/models/send-events.model.ts +2 -2
  177. package/src/db/models/sends.model.ts +7 -8
  178. package/src/db/models/templates.model.ts +64 -16
  179. package/src/db/tables/index.ts +0 -1
  180. package/src/db/tables/settings.table.ts +0 -8
  181. package/src/db/tables/templates.table.ts +12 -17
  182. package/src/engine/formats.ts +124 -0
  183. package/src/engine/index.ts +1 -0
  184. package/src/engine/resolve.ts +18 -7
  185. package/src/engine/tokens.ts +7 -5
  186. package/src/frontend-module.ts +36 -0
  187. package/src/hooks/index.ts +0 -1
  188. package/src/hooks/tenant-export.ts +8 -1
  189. package/src/implementations/dms-mailing/index.ts +5 -16
  190. package/src/index.ts +3 -29
  191. package/src/pages/overview.ts +20 -16
  192. package/src/pages/sends.ts +27 -11
  193. package/src/pages/settings/form.ts +16 -0
  194. package/src/pages/templates.ts +4 -8
  195. package/src/pages/toolbar.ts +77 -0
  196. package/src/realtime.ts +17 -8
  197. package/src/routes/metrics.ts +158 -45
  198. package/src/routes/period.ts +32 -0
  199. package/src/routes/sends.ts +13 -4
  200. package/src/routes/settings.ts +11 -8
  201. package/src/routes/templates.ts +81 -37
  202. package/src/services/categories.ts +14 -1
  203. package/src/services/declarations.ts +64 -317
  204. package/src/services/events.ts +1 -1
  205. package/src/services/localized-text.ts +53 -0
  206. package/src/services/send-import.ts +2 -2
  207. package/src/services/send-stat-items.ts +60 -13
  208. package/src/services/send-stats.ts +37 -5
  209. package/src/services/send.ts +19 -20
  210. package/src/services/sender-declaration.ts +27 -0
  211. package/src/services/settings.ts +3 -10
  212. package/src/services/starters.ts +3 -15
  213. package/src/services/templates.ts +109 -63
  214. package/src/services/webhook-status.ts +3 -3
  215. package/src/types/settings.ts +55 -5
  216. package/src/validation/declarations.schema.ts +29 -3
  217. package/src/validation/settings.schema.ts +56 -14
  218. package/src/validation/templates.schema.ts +10 -0
  219. package/dist/db/models/template-slugs.model.d.ts +0 -27
  220. package/dist/db/models/template-slugs.model.js +0 -43
  221. package/dist/db/models/template-slugs.model.js.map +0 -1
  222. package/dist/db/tables/template-slugs.table.d.ts +0 -7
  223. package/dist/db/tables/template-slugs.table.js +0 -35
  224. package/dist/db/tables/template-slugs.table.js.map +0 -1
  225. package/dist/hooks/database-ready.d.ts +0 -7
  226. package/dist/hooks/database-ready.js +0 -26
  227. package/dist/hooks/database-ready.js.map +0 -1
  228. package/dist/services/fingerprint.d.ts +0 -1
  229. package/dist/services/fingerprint.js +0 -20
  230. package/dist/services/fingerprint.js.map +0 -1
  231. package/frontend-vue/app/components/PageHeader.vue +0 -94
  232. package/frontend-vue/app/composables/useOverviewSetup.ts +0 -21
  233. package/src/db/models/template-slugs.model.ts +0 -61
  234. package/src/db/tables/template-slugs.table.ts +0 -29
  235. package/src/hooks/database-ready.ts +0 -47
  236. package/src/services/fingerprint.ts +0 -22
@@ -1,35 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.MailingTemplateSlug = exports.MAILING_TEMPLATE_SLUGS_TABLE_NAME = void 0;
13
- const interface_database_decorators_1 = require("@antelopejs/interface-database-decorators");
14
- const constants_1 = require("@antelopejs/interface-dms/constants");
15
- exports.MAILING_TEMPLATE_SLUGS_TABLE_NAME = "mailing_template_slugs";
16
- let MailingTemplateSlug = class MailingTemplateSlug extends interface_database_decorators_1.Table {
17
- };
18
- exports.MailingTemplateSlug = MailingTemplateSlug;
19
- __decorate([
20
- (0, interface_database_decorators_1.Field)("string"),
21
- __metadata("design:type", String)
22
- ], MailingTemplateSlug.prototype, "_id", void 0);
23
- __decorate([
24
- (0, interface_database_decorators_1.Field)("string"),
25
- __metadata("design:type", String)
26
- ], MailingTemplateSlug.prototype, "slug", void 0);
27
- __decorate([
28
- (0, interface_database_decorators_1.Index)(),
29
- (0, interface_database_decorators_1.Field)("string"),
30
- __metadata("design:type", String)
31
- ], MailingTemplateSlug.prototype, "templateId", void 0);
32
- exports.MailingTemplateSlug = MailingTemplateSlug = __decorate([
33
- (0, interface_database_decorators_1.RegisterTable)(exports.MAILING_TEMPLATE_SLUGS_TABLE_NAME, constants_1.TENANT_SCHEMA_NAME)
34
- ], MailingTemplateSlug);
35
- //# sourceMappingURL=template-slugs.table.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"template-slugs.table.js","sourceRoot":"","sources":["../../../src/db/tables/template-slugs.table.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6FAKmD;AACnD,mEAAyE;AAE5D,QAAA,iCAAiC,GAAG,wBAAwB,CAAC;AASnE,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,qCAAK;CAW7C,CAAA;AAXY,kDAAmB;AAEtB;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;gDACI;AAGZ;IADP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;iDACK;AAKb;IAFP,IAAA,qCAAK,GAAE;IACP,IAAA,qCAAK,EAAC,QAAQ,CAAC;;uDACW;8BAVhB,mBAAmB;IAD/B,IAAA,6CAAa,EAAC,yCAAiC,EAAE,8BAAkB,CAAC;GACxD,mBAAmB,CAW/B"}
@@ -1,7 +0,0 @@
1
- export interface ReadyGate {
2
- open(): void;
3
- after<Args extends unknown[], Result>(task: (...args: Args) => Promise<Result>): (...args: Args) => Promise<Result>;
4
- }
5
- export declare function createReadyGate(): ReadyGate;
6
- export declare function registerDatabaseReady(): void;
7
- export declare const afterDatabaseReady: ReadyGate["after"];
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.afterDatabaseReady = void 0;
4
- exports.createReadyGate = createReadyGate;
5
- exports.registerDatabaseReady = registerDatabaseReady;
6
- const hooks_1 = require("@antelopejs/interface-dms/hooks");
7
- function createReadyGate() {
8
- let open = () => undefined;
9
- const opened = new Promise((resolve) => {
10
- open = resolve;
11
- });
12
- return {
13
- open: () => open(),
14
- after: (task) => async (...args) => {
15
- await opened;
16
- return task(...args);
17
- },
18
- };
19
- }
20
- const databaseGate = createReadyGate();
21
- function registerDatabaseReady() {
22
- (0, hooks_1.RegisterHook)(hooks_1.Hook.DATABASE_INITIALIZED, () => databaseGate.open());
23
- }
24
- const afterDatabaseReady = (task) => databaseGate.after(task);
25
- exports.afterDatabaseReady = afterDatabaseReady;
26
- //# sourceMappingURL=database-ready.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"database-ready.js","sourceRoot":"","sources":["../../src/hooks/database-ready.ts"],"names":[],"mappings":";;;AAWA,0CAcC;AAeD,sDAEC;AA1CD,2DAAqE;AAWrE,SAAgB,eAAe;IAC7B,IAAI,IAAI,GAAe,GAAG,EAAE,CAAC,SAAS,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC3C,IAAI,GAAG,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE;QAClB,KAAK,EACH,CAAC,IAAI,EAAE,EAAE,CACT,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;YAChB,MAAM,MAAM,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACvB,CAAC;KACJ,CAAC;AACJ,CAAC;AAOD,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;AAQvC,SAAgB,qBAAqB;IACnC,IAAA,oBAAY,EAAC,YAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;AACrE,CAAC;AAGM,MAAM,kBAAkB,GAAuB,CAAC,IAAI,EAAE,EAAE,CAC7D,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AADd,QAAA,kBAAkB,sBACJ"}
@@ -1 +0,0 @@
1
- export declare function fingerprintOf(value: unknown): string;
@@ -1,20 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fingerprintOf = fingerprintOf;
4
- const node_crypto_1 = require("node:crypto");
5
- function stableJson(value) {
6
- if (Array.isArray(value))
7
- return `[${value.map(stableJson).join(",")}]`;
8
- if (value && typeof value === "object") {
9
- const entries = Object.entries(value)
10
- .filter(([, entry]) => entry !== undefined)
11
- .sort(([left], [right]) => Number(left > right) - Number(left < right))
12
- .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`);
13
- return `{${entries.join(",")}}`;
14
- }
15
- return JSON.stringify(value);
16
- }
17
- function fingerprintOf(value) {
18
- return (0, node_crypto_1.createHash)("sha256").update(stableJson(value)).digest("hex");
19
- }
20
- //# sourceMappingURL=fingerprint.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/services/fingerprint.ts"],"names":[],"mappings":";;AAmBA,sCAEC;AArBD,6CAAyC;AAGzC,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACxE,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;aAC7D,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;aAC1C,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;aACtE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAMD,SAAgB,aAAa,CAAC,KAAc;IAC1C,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACtE,CAAC"}
@@ -1,94 +0,0 @@
1
- <script setup lang="ts">
2
- import { useProviderInfo } from '../composables/useMailingReads'
3
- import { useSetupHidesPeriod } from '../composables/useOverviewSetup'
4
- import { presetShortLabelKey } from '../utils/period'
5
- import type { Component } from 'vue'
6
- import type { MailingComponentProps } from '../types/component'
7
- import type { ProviderInfo } from '../types/mailing'
8
-
9
- interface PageHeaderProps extends MailingComponentProps {
10
- periodScope?: string
11
- presets?: string[]
12
- defaultPreset?: string
13
- defaultComparison?: string
14
- showProvider?: boolean
15
- }
16
-
17
- defineOptions({ inheritAttrs: false })
18
-
19
- const PERIOD_COMPONENT_SUFFIX = ':period'
20
-
21
- const props = withDefaults(defineProps<PageHeaderProps>(), {
22
- periodScope: undefined,
23
- presets: () => [],
24
- defaultPreset: undefined,
25
- defaultComparison: undefined,
26
- showProvider: true,
27
- })
28
-
29
- const { t } = useI18n()
30
-
31
- const StatusPill = resolveComponent('DmsStatusPill') as Component
32
- const PeriodSelector = resolveComponent('DmsPeriodSelector') as Component
33
-
34
- /** Shown as "no provider" when the read fails. */
35
- const NO_PROVIDER: ProviderInfo = { name: '', connected: false, features: null }
36
-
37
- const providerRead = useProviderInfo(() => props.showProvider)
38
- const provider = computed<ProviderInfo | null>(() =>
39
- providerRead.error.value ? NO_PROVIDER : providerRead.data.value,
40
- )
41
- const hidesPeriod = useSetupHidesPeriod(props.periodScope)
42
-
43
- const presetLabels = computed(() =>
44
- Object.fromEntries(
45
- props.presets.map((preset) => [preset, t(presetShortLabelKey(preset))]),
46
- ),
47
- )
48
-
49
- const providerPill = computed(() =>
50
- provider.value?.connected
51
- ? {
52
- tone: 'success',
53
- dot: 'live',
54
- label: t('dms_mailing.page_header.provider_connected', {
55
- name: provider.value.name,
56
- }),
57
- }
58
- : {
59
- tone: 'warning',
60
- dot: 'static',
61
- label: t('dms_mailing.page_header.no_provider'),
62
- },
63
- )
64
-
65
- function renderProvider() {
66
- if (!props.showProvider || !provider.value) return null
67
- return h(StatusPill, {
68
- ...providerPill.value,
69
- title: t('dms_mailing.page_header.provider_hint'),
70
- })
71
- }
72
-
73
- function renderPeriod() {
74
- if (!props.periodScope || hidesPeriod.value) return null
75
- return h(PeriodSelector, {
76
- id: props.periodScope,
77
- componentId: `${props.componentId ?? props.periodScope}${PERIOD_COMPONENT_SUFFIX}`,
78
- pageId: props.pageId ?? '',
79
- variant: 'segmented',
80
- size: 'sm',
81
- showRangeLabel: false,
82
- presets: props.presets.length ? props.presets : undefined,
83
- presetLabels: presetLabels.value,
84
- defaultPreset: props.defaultPreset,
85
- defaultComparison: props.defaultComparison,
86
- })
87
- }
88
-
89
- usePageHeaderActions(() => [renderProvider(), renderPeriod()])
90
- </script>
91
-
92
- <template>
93
- <span hidden />
94
- </template>
@@ -1,21 +0,0 @@
1
- import { computed, type ComputedRef } from 'vue'
2
- import { useSetupFacts } from './useMailingReads'
3
- import { needsSetup } from '../utils/overview-setup'
4
-
5
- /** The period scope of the Overview page, whose dashboard the setup gates. */
6
- const OVERVIEW_PERIOD_SCOPE = 'mailing-overview'
7
-
8
- /**
9
- * Whether the page header should hold its period selector back for `scope`:
10
- * on the Overview, while the setup card stands in for the dashboard, there is
11
- * no figure for a period to filter. Read from the setup facts the Overview
12
- * gate shows (one request for both), so a server render hides it as the
13
- * browser does.
14
- */
15
- export function useSetupHidesPeriod(
16
- scope: string | undefined,
17
- ): ComputedRef<boolean> {
18
- if (scope !== OVERVIEW_PERIOD_SCOPE) return computed(() => false)
19
- const { data } = useSetupFacts()
20
- return computed(() => !!data.value && needsSetup(data.value))
21
- }
@@ -1,61 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { BasicDataModel } from "@antelopejs/interface-database-decorators";
3
- import {
4
- MAILING_TEMPLATE_SLUGS_TABLE_NAME,
5
- MailingTemplateSlug,
6
- } from "../tables";
7
-
8
- const ID_LENGTH = 32;
9
-
10
- /**
11
- * The id of a slug's claim, the same whoever creates the template. The tenant
12
- * is part of it: a driver may keep every tenant's rows in one collection,
13
- * where a key made of the slug alone would collide across tenants.
14
- */
15
- export function templateSlugIdOf(tenantId: string, slug: string): string {
16
- return createHash("sha256")
17
- .update(`${tenantId}\n${slug}`)
18
- .digest("hex")
19
- .slice(0, ID_LENGTH);
20
- }
21
-
22
- export class TemplateSlugModel extends BasicDataModel(
23
- MailingTemplateSlug,
24
- MAILING_TEMPLATE_SLUGS_TABLE_NAME,
25
- ) {
26
- /**
27
- * Inserts the claim; false when the key is taken. Probed by state rather
28
- * than by error, since the database interface exposes no typed conflict
29
- * error: a claim present after a failed insert is the lost race.
30
- */
31
- async insertClaim(
32
- id: string,
33
- slug: string,
34
- templateId: string,
35
- ): Promise<boolean> {
36
- try {
37
- await this.insert({ _id: id, slug, templateId });
38
- return true;
39
- } catch (error) {
40
- if (await this.get(id)) return false;
41
- throw error;
42
- }
43
- }
44
-
45
- /** Drops the claim if `templateId` still holds it, never a newer one. */
46
- async dropClaimOf(id: string, templateId: string): Promise<void> {
47
- await this.table
48
- .atomicMutation(id, {
49
- type: "deleteIfEqual",
50
- field: "templateId",
51
- expectedValue: templateId,
52
- })
53
- .run();
54
- }
55
-
56
- /** Frees the slugs the templates held. */
57
- async releaseTemplates(templateIds: string[]): Promise<void> {
58
- if (!templateIds.length) return;
59
- await this.table.getAll(templateIds, "templateId").delete().run();
60
- }
61
- }
@@ -1,29 +0,0 @@
1
- import {
2
- Field,
3
- Index,
4
- RegisterTable,
5
- Table,
6
- } from "@antelopejs/interface-database-decorators";
7
- import { TENANT_SCHEMA_NAME } from "@antelopejs/interface-dms/constants";
8
-
9
- export const MAILING_TEMPLATE_SLUGS_TABLE_NAME = "mailing_template_slugs";
10
-
11
- /**
12
- * The template a slug belongs to. Its id derives from the tenant and the
13
- * slug, so the primary key is what keeps a slug to one template: the database
14
- * interface declares no unique secondary index, and two creations racing
15
- * past the free-slug check both insert their template, but only one claim.
16
- */
17
- @RegisterTable(MAILING_TEMPLATE_SLUGS_TABLE_NAME, TENANT_SCHEMA_NAME)
18
- export class MailingTemplateSlug extends Table {
19
- @Field("string")
20
- declare _id: string;
21
-
22
- @Field("string")
23
- declare slug: string;
24
-
25
- /** The template holding the slug; a deleted one leaves the claim free. */
26
- @Index()
27
- @Field("string")
28
- declare templateId: string;
29
- }
@@ -1,47 +0,0 @@
1
- import { Hook, RegisterHook } from "@antelopejs/interface-dms/hooks";
2
-
3
- /** A promise opened once, and the calls that wait for it. */
4
- export interface ReadyGate {
5
- open(): void;
6
- /** `task`, run once the gate is open. */
7
- after<Args extends unknown[], Result>(
8
- task: (...args: Args) => Promise<Result>,
9
- ): (...args: Args) => Promise<Result>;
10
- }
11
-
12
- export function createReadyGate(): ReadyGate {
13
- let open: () => void = () => undefined;
14
- const opened = new Promise<void>((resolve) => {
15
- open = resolve;
16
- });
17
- return {
18
- open: () => open(),
19
- after:
20
- (task) =>
21
- async (...args) => {
22
- await opened;
23
- return task(...args);
24
- },
25
- };
26
- }
27
-
28
- /**
29
- * Opens once the DMS reports its schemas registered, which it does from its
30
- * own `start()`. Modules construct and start in parallel, so a project
31
- * declaring its content early waits here instead of failing.
32
- */
33
- const databaseGate = createReadyGate();
34
-
35
- /**
36
- * The DMS fires the hook on every start and runs a handler registered after
37
- * that at once: whatever the load order, the first firing opens the gate.
38
- * Its handlers run in series, so this one is registered first thing in
39
- * `construct()`, ahead of handlers that may wait on the gate.
40
- */
41
- export function registerDatabaseReady(): void {
42
- RegisterHook(Hook.DATABASE_INITIALIZED, () => databaseGate.open());
43
- }
44
-
45
- /** `task`, run once the database is ready. */
46
- export const afterDatabaseReady: ReadyGate["after"] = (task) =>
47
- databaseGate.after(task);
@@ -1,22 +0,0 @@
1
- import { createHash } from "node:crypto";
2
-
3
- /** JSON with object keys sorted, so equal values always serialize alike. */
4
- function stableJson(value: unknown): string {
5
- if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
6
- if (value && typeof value === "object") {
7
- const entries = Object.entries(value as Record<string, unknown>)
8
- .filter(([, entry]) => entry !== undefined)
9
- .sort(([left], [right]) => Number(left > right) - Number(left < right))
10
- .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`);
11
- return `{${entries.join(",")}}`;
12
- }
13
- return JSON.stringify(value);
14
- }
15
-
16
- /**
17
- * A short digest of `value` that ignores key order: what a declaration
18
- * remembers of what it wrote, to tell later whether a user changed it.
19
- */
20
- export function fingerprintOf(value: unknown): string {
21
- return createHash("sha256").update(stableJson(value)).digest("hex");
22
- }