@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.
- package/README.md +8 -7
- package/dist/constants.d.ts +1 -2
- package/dist/constants.js +2 -3
- package/dist/constants.js.map +1 -1
- package/dist/data/templates-table.d.ts +4 -1
- package/dist/data/templates-table.js +55 -20
- package/dist/data/templates-table.js.map +1 -1
- package/dist/data-types/categories-type.d.ts +5 -5
- package/dist/db/models/index.d.ts +0 -1
- package/dist/db/models/index.js +0 -1
- package/dist/db/models/index.js.map +1 -1
- package/dist/db/models/send-events.model.js +2 -3
- package/dist/db/models/send-events.model.js.map +1 -1
- package/dist/db/models/sends.model.js +2 -3
- package/dist/db/models/sends.model.js.map +1 -1
- package/dist/db/models/templates.model.d.ts +10 -1
- package/dist/db/models/templates.model.js +29 -10
- package/dist/db/models/templates.model.js.map +1 -1
- package/dist/db/tables/index.d.ts +0 -1
- package/dist/db/tables/index.js +0 -1
- package/dist/db/tables/index.js.map +1 -1
- package/dist/db/tables/settings.table.d.ts +0 -1
- package/dist/db/tables/settings.table.js +0 -4
- package/dist/db/tables/settings.table.js.map +1 -1
- package/dist/db/tables/templates.table.d.ts +7 -4
- package/dist/db/tables/templates.table.js +4 -14
- package/dist/db/tables/templates.table.js.map +1 -1
- package/dist/engine/formats.d.ts +13 -0
- package/dist/engine/formats.js +85 -0
- package/dist/engine/formats.js.map +1 -0
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.js +1 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/resolve.d.ts +2 -1
- package/dist/engine/resolve.js +14 -7
- package/dist/engine/resolve.js.map +1 -1
- package/dist/engine/tokens.d.ts +2 -1
- package/dist/engine/tokens.js +3 -5
- package/dist/engine/tokens.js.map +1 -1
- package/dist/frontend-module.d.ts +2 -0
- package/dist/frontend-module.js +24 -0
- package/dist/frontend-module.js.map +1 -0
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/index.js +0 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tenant-export.js +4 -1
- package/dist/hooks/tenant-export.js.map +1 -1
- package/dist/implementations/dms-mailing/index.d.ts +3 -3
- package/dist/implementations/dms-mailing/index.js +8 -7
- package/dist/implementations/dms-mailing/index.js.map +1 -1
- package/dist/index.js +2 -20
- package/dist/index.js.map +1 -1
- package/dist/pages/overview.d.ts +1 -1
- package/dist/pages/overview.js +11 -13
- package/dist/pages/overview.js.map +1 -1
- package/dist/pages/sends.d.ts +1 -1
- package/dist/pages/sends.js +16 -8
- package/dist/pages/sends.js.map +1 -1
- package/dist/pages/settings/form.js +8 -0
- package/dist/pages/settings/form.js.map +1 -1
- package/dist/pages/templates.js +3 -8
- package/dist/pages/templates.js.map +1 -1
- package/dist/pages/toolbar.d.ts +12 -0
- package/dist/pages/toolbar.js +41 -0
- package/dist/pages/toolbar.js.map +1 -0
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js +8 -8
- package/dist/realtime.js.map +1 -1
- package/dist/routes/metrics.d.ts +9 -2
- package/dist/routes/metrics.js +90 -35
- package/dist/routes/metrics.js.map +1 -1
- package/dist/routes/period.d.ts +1 -0
- package/dist/routes/period.js +19 -0
- package/dist/routes/period.js.map +1 -1
- package/dist/routes/sends.js +6 -3
- package/dist/routes/sends.js.map +1 -1
- package/dist/routes/settings.js +6 -7
- package/dist/routes/settings.js.map +1 -1
- package/dist/routes/templates.d.ts +8 -4
- package/dist/routes/templates.js +41 -20
- package/dist/routes/templates.js.map +1 -1
- package/dist/services/categories.d.ts +2 -1
- package/dist/services/categories.js +9 -0
- package/dist/services/categories.js.map +1 -1
- package/dist/services/declarations.js +42 -184
- package/dist/services/declarations.js.map +1 -1
- package/dist/services/events.js +1 -1
- package/dist/services/events.js.map +1 -1
- package/dist/services/localized-text.d.ts +7 -0
- package/dist/services/localized-text.js +28 -0
- package/dist/services/localized-text.js.map +1 -0
- package/dist/services/send-import.js +0 -2
- package/dist/services/send-import.js.map +1 -1
- package/dist/services/send-stat-items.js +34 -12
- package/dist/services/send-stat-items.js.map +1 -1
- package/dist/services/send-stats.d.ts +7 -0
- package/dist/services/send-stats.js +17 -5
- package/dist/services/send-stats.js.map +1 -1
- package/dist/services/send.d.ts +2 -0
- package/dist/services/send.js +11 -12
- package/dist/services/send.js.map +1 -1
- package/dist/services/sender-declaration.d.ts +2 -0
- package/dist/services/sender-declaration.js +18 -0
- package/dist/services/sender-declaration.js.map +1 -0
- package/dist/services/settings.d.ts +1 -1
- package/dist/services/settings.js +1 -5
- package/dist/services/settings.js.map +1 -1
- package/dist/services/starters.d.ts +2 -2
- package/dist/services/starters.js +1 -10
- package/dist/services/starters.js.map +1 -1
- package/dist/services/templates.d.ts +13 -7
- package/dist/services/templates.js +72 -33
- package/dist/services/templates.js.map +1 -1
- package/dist/services/webhook-status.d.ts +2 -1
- package/dist/services/webhook-status.js +6 -5
- package/dist/services/webhook-status.js.map +1 -1
- package/dist/types/settings.d.ts +8 -0
- package/dist/types/settings.js +33 -6
- package/dist/types/settings.js.map +1 -1
- package/dist/validation/declarations.schema.d.ts +25 -7
- package/dist/validation/declarations.schema.js +16 -3
- package/dist/validation/declarations.schema.js.map +1 -1
- package/dist/validation/settings.schema.d.ts +41 -41
- package/dist/validation/settings.schema.js +30 -6
- package/dist/validation/settings.schema.js.map +1 -1
- package/dist/validation/templates.schema.d.ts +13 -0
- package/dist/validation/templates.schema.js +6 -1
- package/dist/validation/templates.schema.js.map +1 -1
- package/frontend-vue/app/components/CategoriesInput.vue +15 -13
- package/frontend-vue/app/components/FunnelCard.vue +46 -3
- package/frontend-vue/app/components/NewTemplateModal.vue +4 -2
- package/frontend-vue/app/components/OverviewGate.vue +0 -8
- package/frontend-vue/app/components/ProviderPill.vue +50 -0
- package/frontend-vue/app/components/SendDrawer.vue +206 -183
- package/frontend-vue/app/components/StarterGallery.vue +1 -1
- package/frontend-vue/app/components/TemplateCard.vue +4 -1
- package/frontend-vue/app/components/TemplateDrawer.vue +3 -5
- package/frontend-vue/app/components/TemplateGallery.vue +57 -17
- package/frontend-vue/app/components/TemplatePreviewFrame.vue +41 -11
- package/frontend-vue/app/components/editor/EditorTemplatePane.vue +1 -3
- package/frontend-vue/app/components/editor/EditorTitle.vue +1 -7
- package/frontend-vue/app/composables/useLocalizedDefaults.ts +5 -7
- package/frontend-vue/app/composables/useMailingApi.ts +3 -3
- package/frontend-vue/app/composables/useMailingReads.ts +2 -2
- package/frontend-vue/app/composables/useTemplateCategories.ts +8 -7
- package/frontend-vue/app/types/mailing.ts +18 -0
- package/frontend-vue/app/utils/categories.ts +58 -49
- package/frontend-vue/app/utils/funnel.ts +25 -0
- package/frontend-vue/app/utils/period.ts +0 -7
- package/frontend-vue/app/utils/starters.ts +3 -1
- package/frontend-vue/app/utils/tokens.ts +6 -1
- package/frontend-vue/i18n/locales/mailing-en-GB.json +19 -28
- package/frontend-vue/i18n/locales/mailing-fr-FR.json +19 -28
- package/frontend-vue/package.json +1 -1
- package/frontend-vue/tests/categories-input.test.ts +4 -10
- package/frontend-vue/tests/categories.test.ts +55 -17
- package/frontend-vue/tests/conditions.test.ts +1 -4
- package/frontend-vue/tests/funnel-card.test.ts +27 -0
- package/frontend-vue/tests/funnel.test.ts +25 -0
- package/frontend-vue/tests/localized-defaults.test.ts +0 -29
- package/frontend-vue/tests/new-template-modal.test.ts +1 -1
- package/frontend-vue/tests/overview-gate.test.ts +1 -24
- package/frontend-vue/tests/page-reads.test.ts +9 -25
- package/frontend-vue/tests/period.test.ts +0 -12
- package/frontend-vue/tests/replay-toast.test.ts +2 -1
- package/frontend-vue/tests/send-drawer.test.ts +123 -0
- package/frontend-vue/tests/template-drawer.test.ts +1 -1
- package/frontend-vue/tests/template-gallery.test.ts +90 -3
- package/frontend-vue/tests/template-preview-frame.test.ts +92 -0
- package/package.json +8 -7
- package/skills/dms-mailing/SKILL.md +25 -18
- package/src/constants.ts +2 -2
- package/src/data/sends-table.ts +1 -1
- package/src/data/templates-table.ts +125 -33
- package/src/db/models/index.ts +0 -1
- package/src/db/models/send-events.model.ts +2 -2
- package/src/db/models/sends.model.ts +7 -8
- package/src/db/models/templates.model.ts +64 -16
- package/src/db/tables/index.ts +0 -1
- package/src/db/tables/settings.table.ts +0 -8
- package/src/db/tables/templates.table.ts +12 -17
- package/src/engine/formats.ts +124 -0
- package/src/engine/index.ts +1 -0
- package/src/engine/resolve.ts +18 -7
- package/src/engine/tokens.ts +7 -5
- package/src/frontend-module.ts +36 -0
- package/src/hooks/index.ts +0 -1
- package/src/hooks/tenant-export.ts +8 -1
- package/src/implementations/dms-mailing/index.ts +5 -16
- package/src/index.ts +3 -29
- package/src/pages/overview.ts +20 -16
- package/src/pages/sends.ts +27 -11
- package/src/pages/settings/form.ts +16 -0
- package/src/pages/templates.ts +4 -8
- package/src/pages/toolbar.ts +77 -0
- package/src/realtime.ts +17 -8
- package/src/routes/metrics.ts +158 -45
- package/src/routes/period.ts +32 -0
- package/src/routes/sends.ts +13 -4
- package/src/routes/settings.ts +11 -8
- package/src/routes/templates.ts +81 -37
- package/src/services/categories.ts +14 -1
- package/src/services/declarations.ts +64 -317
- package/src/services/events.ts +1 -1
- package/src/services/localized-text.ts +53 -0
- package/src/services/send-import.ts +2 -2
- package/src/services/send-stat-items.ts +60 -13
- package/src/services/send-stats.ts +37 -5
- package/src/services/send.ts +19 -20
- package/src/services/sender-declaration.ts +27 -0
- package/src/services/settings.ts +3 -10
- package/src/services/starters.ts +3 -15
- package/src/services/templates.ts +109 -63
- package/src/services/webhook-status.ts +3 -3
- package/src/types/settings.ts +55 -5
- package/src/validation/declarations.schema.ts +29 -3
- package/src/validation/settings.schema.ts +56 -14
- package/src/validation/templates.schema.ts +10 -0
- package/dist/db/models/template-slugs.model.d.ts +0 -27
- package/dist/db/models/template-slugs.model.js +0 -43
- package/dist/db/models/template-slugs.model.js.map +0 -1
- package/dist/db/tables/template-slugs.table.d.ts +0 -7
- package/dist/db/tables/template-slugs.table.js +0 -35
- package/dist/db/tables/template-slugs.table.js.map +0 -1
- package/dist/hooks/database-ready.d.ts +0 -7
- package/dist/hooks/database-ready.js +0 -26
- package/dist/hooks/database-ready.js.map +0 -1
- package/dist/services/fingerprint.d.ts +0 -1
- package/dist/services/fingerprint.js +0 -20
- package/dist/services/fingerprint.js.map +0 -1
- package/frontend-vue/app/components/PageHeader.vue +0 -94
- package/frontend-vue/app/composables/useOverviewSetup.ts +0 -21
- package/src/db/models/template-slugs.model.ts +0 -61
- package/src/db/tables/template-slugs.table.ts +0 -29
- package/src/hooks/database-ready.ts +0 -47
- package/src/services/fingerprint.ts +0 -22
package/src/routes/templates.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
JSONBody,
|
|
6
6
|
Parameter,
|
|
7
7
|
Post,
|
|
8
|
+
Put,
|
|
8
9
|
type RequestContext,
|
|
9
10
|
} from "@antelopejs/interface-api";
|
|
10
11
|
import { assert, assertValidation } from "@antelopejs/interface-api-util";
|
|
@@ -22,12 +23,21 @@ import {
|
|
|
22
23
|
collectContentVariablePaths,
|
|
23
24
|
resolveEmail,
|
|
24
25
|
type TemplateChange,
|
|
26
|
+
valueFormatOf,
|
|
25
27
|
} from "../engine";
|
|
26
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
type MailingTemplate,
|
|
30
|
+
SendModel,
|
|
31
|
+
type TemplateFields,
|
|
32
|
+
TemplateModel,
|
|
33
|
+
} from "../db";
|
|
34
|
+
import { saveDetails } from "../data/templates-table";
|
|
27
35
|
import { TemplatesPageController } from "../pages/templates";
|
|
28
36
|
import { forAudience, statsWindowStart } from "../services/metrics";
|
|
29
37
|
import { refreshTemplateAttention } from "../services/template-attention";
|
|
30
38
|
import { renderEmailHtml } from "../services/render";
|
|
39
|
+
import { categoriesIn } from "../services/categories";
|
|
40
|
+
import { localeOfRequest, withTextIn } from "../services/localized-text";
|
|
31
41
|
import { getSettings } from "../services/settings";
|
|
32
42
|
import { findStarter, STARTER_TEMPLATES } from "../services/starters";
|
|
33
43
|
import {
|
|
@@ -37,9 +47,7 @@ import {
|
|
|
37
47
|
type TemplateStats,
|
|
38
48
|
} from "../services/template-stats";
|
|
39
49
|
import {
|
|
40
|
-
assertSlugClaimed,
|
|
41
50
|
contentFieldsOf,
|
|
42
|
-
contentOfVersion,
|
|
43
51
|
discardDraft,
|
|
44
52
|
displayName,
|
|
45
53
|
hasDraft,
|
|
@@ -55,13 +63,18 @@ import {
|
|
|
55
63
|
publishedVersionOf,
|
|
56
64
|
publishTemplate,
|
|
57
65
|
saveDraft,
|
|
66
|
+
publishedSnapshot,
|
|
67
|
+
snapshotOfVersion,
|
|
68
|
+
type TemplateDraft,
|
|
69
|
+
workingSnapshot,
|
|
58
70
|
workingContent,
|
|
59
71
|
workingVariables,
|
|
72
|
+
refuseTakenSlug,
|
|
60
73
|
requireTemplate,
|
|
61
74
|
} from "../services/templates";
|
|
62
75
|
import {
|
|
63
76
|
BUSINESS_AUDIENCE,
|
|
64
|
-
type
|
|
77
|
+
type CategoryInLocale,
|
|
65
78
|
type TemplateContent,
|
|
66
79
|
type TemplateStatus,
|
|
67
80
|
type VariableDefinition,
|
|
@@ -76,7 +89,6 @@ import {
|
|
|
76
89
|
} from "../validation/templates.schema";
|
|
77
90
|
|
|
78
91
|
const STARTER_NOT_FOUND = "$dms_mailing.errors.starter_not_found";
|
|
79
|
-
const DUPLICATE_SLUG = "$dms_mailing.errors.duplicate_slug";
|
|
80
92
|
const INVALID_CONTENT = "$dms_mailing.errors.invalid_content";
|
|
81
93
|
const INVALID_TRANSITION = "$dms_mailing.errors.invalid_transition";
|
|
82
94
|
const NOTHING_TO_PUBLISH = "$dms_mailing.errors.nothing_to_publish";
|
|
@@ -104,14 +116,13 @@ const TARGET_STATUS: Record<
|
|
|
104
116
|
};
|
|
105
117
|
|
|
106
118
|
/** What a lifecycle action records besides the new status. */
|
|
107
|
-
const TRANSITION_FIELDS: Partial<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
};
|
|
119
|
+
const TRANSITION_FIELDS: Partial<Record<TemplateAction, () => TemplateFields>> =
|
|
120
|
+
{
|
|
121
|
+
unpublish: () => ({ unpublishedAt: new Date() }),
|
|
122
|
+
};
|
|
112
123
|
|
|
113
124
|
export interface CategoriesResponse {
|
|
114
|
-
categories:
|
|
125
|
+
categories: CategoryInLocale[];
|
|
115
126
|
}
|
|
116
127
|
|
|
117
128
|
export interface TemplateSender {
|
|
@@ -121,6 +132,7 @@ export interface TemplateSender {
|
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
export interface TemplateContentResponse {
|
|
135
|
+
/** The template, its name in the reader's language. */
|
|
124
136
|
template: MailingTemplate;
|
|
125
137
|
/** The content the editor works on: the draft, else the published one. */
|
|
126
138
|
content: TemplateContent;
|
|
@@ -146,7 +158,7 @@ export interface TemplateContentResponse {
|
|
|
146
158
|
fallbackLocale: string;
|
|
147
159
|
/** Whether a send missing a variable fails rather than goes out blank. */
|
|
148
160
|
blockOnMissingVariables: boolean;
|
|
149
|
-
categories:
|
|
161
|
+
categories: CategoryInLocale[];
|
|
150
162
|
sender: TemplateSender;
|
|
151
163
|
}
|
|
152
164
|
|
|
@@ -192,6 +204,11 @@ export class TemplatesController extends Controller(
|
|
|
192
204
|
return displayName(this.user);
|
|
193
205
|
}
|
|
194
206
|
|
|
207
|
+
/** The language the reader reads names and labels in. */
|
|
208
|
+
private get locale(): string {
|
|
209
|
+
return localeOfRequest(this.ctx);
|
|
210
|
+
}
|
|
211
|
+
|
|
195
212
|
/**
|
|
196
213
|
* The tenant's categories for a category picker. Separate from `/settings`,
|
|
197
214
|
* which is guarded by the settings page permission a template editor need
|
|
@@ -200,7 +217,7 @@ export class TemplatesController extends Controller(
|
|
|
200
217
|
@Get("/categories")
|
|
201
218
|
async categories(): Promise<CategoriesResponse> {
|
|
202
219
|
const settings = await getSettings(this.tenantId);
|
|
203
|
-
return { categories: settings.categories };
|
|
220
|
+
return { categories: categoriesIn(settings.categories, this.locale) };
|
|
204
221
|
}
|
|
205
222
|
|
|
206
223
|
@Get("/starters")
|
|
@@ -236,7 +253,12 @@ export class TemplatesController extends Controller(
|
|
|
236
253
|
);
|
|
237
254
|
const localeContent = localeContentOf(starter.content, locale);
|
|
238
255
|
assert(localeContent, HTTP_UNPROCESSABLE, INVALID_CONTENT);
|
|
239
|
-
const email = resolveEmail(
|
|
256
|
+
const email = resolveEmail(
|
|
257
|
+
localeContent,
|
|
258
|
+
starter.testDataFor(locale),
|
|
259
|
+
undefined,
|
|
260
|
+
valueFormatOf(locale, starter.variables),
|
|
261
|
+
);
|
|
240
262
|
return { html: await renderEmailHtml(email, locale), locale };
|
|
241
263
|
}
|
|
242
264
|
|
|
@@ -289,7 +311,7 @@ export class TemplatesController extends Controller(
|
|
|
289
311
|
? parseContent(template)
|
|
290
312
|
: null;
|
|
291
313
|
return {
|
|
292
|
-
template,
|
|
314
|
+
template: template.localize(this.locale, ["name"]),
|
|
293
315
|
content,
|
|
294
316
|
publishedContent,
|
|
295
317
|
hasDraft: hasDraft(template),
|
|
@@ -305,7 +327,7 @@ export class TemplatesController extends Controller(
|
|
|
305
327
|
testData: parseTestData(template),
|
|
306
328
|
fallbackLocale: settings.fallbackLocale,
|
|
307
329
|
blockOnMissingVariables: settings.blockOnMissingVariables,
|
|
308
|
-
categories: settings.categories,
|
|
330
|
+
categories: categoriesIn(settings.categories, this.locale),
|
|
309
331
|
sender: {
|
|
310
332
|
name: settings.senderName,
|
|
311
333
|
email: settings.senderEmail,
|
|
@@ -431,7 +453,7 @@ export class TemplatesController extends Controller(
|
|
|
431
453
|
) {
|
|
432
454
|
await this.requireTransition(id, action);
|
|
433
455
|
const status = TARGET_STATUS[action];
|
|
434
|
-
await this.templates.
|
|
456
|
+
await this.templates.updateFields(id, {
|
|
435
457
|
status,
|
|
436
458
|
updatedBy: this.author,
|
|
437
459
|
...TRANSITION_FIELDS[action]?.(),
|
|
@@ -472,7 +494,9 @@ export class TemplatesController extends Controller(
|
|
|
472
494
|
testDataSchema.parse(value),
|
|
473
495
|
);
|
|
474
496
|
await requireTemplate(this.templates, id);
|
|
475
|
-
await this.templates.
|
|
497
|
+
await this.templates.updateFields(id, {
|
|
498
|
+
json_test_data: JSON.stringify(data),
|
|
499
|
+
});
|
|
476
500
|
return { data };
|
|
477
501
|
}
|
|
478
502
|
|
|
@@ -487,9 +511,12 @@ export class TemplatesController extends Controller(
|
|
|
487
511
|
() => INVALID_CONTENT,
|
|
488
512
|
);
|
|
489
513
|
const template = await requireTemplate(this.templates, id);
|
|
490
|
-
const content =
|
|
491
|
-
|
|
492
|
-
|
|
514
|
+
const { content, variables } = input.content
|
|
515
|
+
? {
|
|
516
|
+
...workingSnapshot(template),
|
|
517
|
+
content: input.content as TemplateContent,
|
|
518
|
+
}
|
|
519
|
+
: await this.previewSnapshot(template, input.version);
|
|
493
520
|
const settings = await getSettings(this.tenantId);
|
|
494
521
|
const locale = pickLocale(content, input.locale, settings.fallbackLocale);
|
|
495
522
|
const localeContent = localeContentOf(content, locale);
|
|
@@ -497,6 +524,8 @@ export class TemplatesController extends Controller(
|
|
|
497
524
|
const email = resolveEmail(
|
|
498
525
|
localeContent,
|
|
499
526
|
input.data ?? parseTestData(template),
|
|
527
|
+
undefined,
|
|
528
|
+
valueFormatOf(locale, variables),
|
|
500
529
|
);
|
|
501
530
|
const html = await renderEmailHtml(email, locale);
|
|
502
531
|
return {
|
|
@@ -508,14 +537,30 @@ export class TemplatesController extends Controller(
|
|
|
508
537
|
};
|
|
509
538
|
}
|
|
510
539
|
|
|
511
|
-
private
|
|
540
|
+
private previewSnapshot(
|
|
512
541
|
template: MailingTemplate,
|
|
513
542
|
version: "draft" | "published" | number | undefined,
|
|
514
|
-
): Promise<
|
|
515
|
-
if (version === "published") return
|
|
543
|
+
): Promise<TemplateDraft> | TemplateDraft {
|
|
544
|
+
if (version === "published") return publishedSnapshot(template);
|
|
516
545
|
if (typeof version === "number")
|
|
517
|
-
return
|
|
518
|
-
return
|
|
546
|
+
return snapshotOfVersion(this.tenantId, template, version);
|
|
547
|
+
return workingSnapshot(template);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Renames a template in the reader's language, its other languages kept,
|
|
552
|
+
* and sets its category: what the module's drawer and editor save, each
|
|
553
|
+
* showing one language. The DMS edit form, which shows every language,
|
|
554
|
+
* writes through the table's edit route.
|
|
555
|
+
*/
|
|
556
|
+
@Put("/:id/details")
|
|
557
|
+
async details(
|
|
558
|
+
@Parameter("id", "param") id: string,
|
|
559
|
+
@JSONBody() body: unknown,
|
|
560
|
+
) {
|
|
561
|
+
const template = await requireTemplate(this.templates, id);
|
|
562
|
+
await saveDetails(this.ctx, template, body, this.author);
|
|
563
|
+
return { id };
|
|
519
564
|
}
|
|
520
565
|
|
|
521
566
|
@Post("/:id/duplicate")
|
|
@@ -527,17 +572,16 @@ export class TemplatesController extends Controller(
|
|
|
527
572
|
duplicateSchema.parse(value),
|
|
528
573
|
);
|
|
529
574
|
const source = await requireTemplate(this.templates, id);
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
await assertSlugClaimed(this.tenantId, slug, copyId as string);
|
|
575
|
+
const [copyId] = await refuseTakenSlug(
|
|
576
|
+
this.templates.insertFields({
|
|
577
|
+
slug,
|
|
578
|
+
name: withTextIn(undefined, this.locale, name),
|
|
579
|
+
category: source.category,
|
|
580
|
+
status: "draft",
|
|
581
|
+
...contentFieldsOf(source),
|
|
582
|
+
updatedBy: this.author,
|
|
583
|
+
}),
|
|
584
|
+
);
|
|
541
585
|
await refreshTemplateAttention(this.tenantId);
|
|
542
586
|
return { id: copyId };
|
|
543
587
|
}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import type { MailingTemplate } from "../db";
|
|
2
|
-
import type { TemplateCategory } from "../types";
|
|
2
|
+
import type { CategoryInLocale, TemplateCategory } from "../types";
|
|
3
3
|
import type { CategoryEntry } from "../validation/settings.schema";
|
|
4
|
+
import { textIn } from "./localized-text";
|
|
5
|
+
|
|
6
|
+
/** The categories as a reader of `locale` sees them. */
|
|
7
|
+
export function categoriesIn(
|
|
8
|
+
categories: TemplateCategory[],
|
|
9
|
+
locale: string,
|
|
10
|
+
): CategoryInLocale[] {
|
|
11
|
+
return categories.map(({ id, label, icon }) => ({
|
|
12
|
+
id,
|
|
13
|
+
label: textIn(label, locale),
|
|
14
|
+
icon,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
4
17
|
|
|
5
18
|
/** The categories a list keeps, without the removed ones it moves away. */
|
|
6
19
|
export function keptCategories(entries: CategoryEntry[]): TemplateCategory[] {
|