@antelopejs/dms-mailing 0.9.1 → 0.10.0
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 +11 -11
- package/dist/data/read-only-routes.d.ts +14 -1
- package/dist/data/sends-table.d.ts +14 -1
- package/dist/data/suppressions-table.d.ts +14 -1
- package/dist/data/templates-table.d.ts +15 -2
- package/dist/db/models/send-events.model.d.ts +3 -3
- package/dist/db/models/sends.model.d.ts +6 -4
- package/dist/db/models/sends.model.js +26 -2
- package/dist/db/models/sends.model.js.map +1 -1
- package/dist/db/models/settings.model.d.ts +3 -3
- package/dist/db/models/suppressions.model.d.ts +3 -3
- package/dist/db/models/template-versions.model.d.ts +3 -3
- package/dist/db/models/template-versions.model.js +2 -3
- package/dist/db/models/template-versions.model.js.map +1 -1
- package/dist/db/models/templates.model.d.ts +4 -3
- package/dist/db/models/templates.model.js +14 -6
- package/dist/db/models/templates.model.js.map +1 -1
- package/dist/db/models/webhook-status.model.d.ts +3 -3
- package/dist/db/tables/templates.table.d.ts +4 -1
- package/dist/hooks/tenant-export.js +5 -1
- package/dist/hooks/tenant-export.js.map +1 -1
- package/dist/pages/editor.js +1 -1
- package/dist/pages/editor.js.map +1 -1
- package/dist/routes/metrics.js +1 -2
- package/dist/routes/metrics.js.map +1 -1
- package/dist/routes/sends.js +2 -1
- package/dist/routes/sends.js.map +1 -1
- package/dist/routes/templates.d.ts +2 -2
- package/dist/routes/templates.js +4 -4
- package/dist/routes/templates.js.map +1 -1
- package/dist/services/attention.d.ts +1 -1
- package/dist/services/attention.js +3 -3
- package/dist/services/attention.js.map +1 -1
- package/dist/services/metrics.js +5 -1
- package/dist/services/metrics.js.map +1 -1
- package/dist/services/settings.js +2 -1
- package/dist/services/settings.js.map +1 -1
- package/dist/services/template-attention.d.ts +1 -1
- package/dist/services/template-attention.js +2 -4
- package/dist/services/template-attention.js.map +1 -1
- package/dist/services/templates.js +10 -8
- package/dist/services/templates.js.map +1 -1
- package/dist/validation/declarations.schema.d.ts +1 -1
- package/dist/validation/stored.schema.d.ts +12 -0
- package/dist/validation/stored.schema.js +198 -0
- package/dist/validation/stored.schema.js.map +1 -0
- package/frontend-vue/app/composables/useEditorContext.ts +1 -1
- package/frontend-vue/build/backend-boundary.ts +7 -2
- package/frontend-vue/dms.frontend.ts +1 -4
- package/frontend-vue/eslint.config.mjs +9 -1
- package/frontend-vue/package.json +1 -1
- package/frontend-vue/pnpm-lock.yaml +24 -7
- package/frontend-vue/tests/backend-boundary.test.ts +4 -4
- package/frontend-vue/tests/column-displays.test.ts +13 -12
- package/frontend-vue/tests/footer-block.test.ts +1 -1
- package/frontend-vue/tests/template-gallery-display.test.ts +6 -5
- package/frontend-vue/tests/template-overlays.test.ts +4 -12
- package/frontend-vue/tsconfig.typecheck.json +1 -2
- package/package.json +16 -16
- package/src/db/models/sends.model.ts +34 -4
- package/src/db/models/template-versions.model.ts +8 -6
- package/src/db/models/templates.model.ts +25 -9
- package/src/hooks/tenant-export.ts +5 -2
- package/src/pages/editor.ts +1 -1
- package/src/routes/metrics.ts +1 -2
- package/src/routes/sends.ts +2 -3
- package/src/routes/templates.ts +9 -9
- package/src/services/attention.ts +6 -6
- package/src/services/metrics.ts +3 -1
- package/src/services/settings.ts +9 -3
- package/src/services/template-attention.ts +4 -5
- package/src/services/templates.ts +35 -16
- package/src/validation/stored.schema.ts +257 -0
- /package/frontend-vue/app/components/{Editor.vue → TemplateEditor.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Button.vue → BlockButton.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Code.vue → BlockCode.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Divider.vue → BlockDivider.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Footer.vue → BlockFooter.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Heading.vue → BlockHeading.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Hero.vue → BlockHero.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{List.vue → BlockList.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Paragraph.vue → BlockParagraph.vue} +0 -0
- /package/frontend-vue/app/components/blocks/{Total.vue → BlockTotal.vue} +0 -0
|
@@ -111,8 +111,8 @@ export declare const senderDeclarationSchema: z.ZodObject<{
|
|
|
111
111
|
name: z.ZodDefault<z.ZodEffects<z.ZodString, string, string>>;
|
|
112
112
|
replyTo: z.ZodDefault<z.ZodPipeline<z.ZodEffects<z.ZodString, string, string>, z.ZodUnion<[z.ZodLiteral<"">, z.ZodString]>>>;
|
|
113
113
|
}, "strip", z.ZodTypeAny, {
|
|
114
|
-
email: string;
|
|
115
114
|
name: string;
|
|
115
|
+
email: string;
|
|
116
116
|
tenantId: string;
|
|
117
117
|
replyTo: string;
|
|
118
118
|
}, {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { MailingTemplateVersion } from "../db/tables";
|
|
3
|
+
import type { TemplateChange } from "../engine/changes";
|
|
4
|
+
import type { TemplateCategory, TemplateContent, VariableDefinition } from "../types";
|
|
5
|
+
type StoredSchema<T> = z.ZodType<T, z.ZodTypeDef, unknown>;
|
|
6
|
+
export declare function parseStored<T>(text: string, schema: StoredSchema<T>, what: string): T;
|
|
7
|
+
export declare const storedContentSchema: StoredSchema<TemplateContent>;
|
|
8
|
+
export declare const storedVariablesSchema: StoredSchema<VariableDefinition[]>;
|
|
9
|
+
export declare const storedChangesSchema: StoredSchema<TemplateChange[]>;
|
|
10
|
+
export declare const storedVersionRowSchema: StoredSchema<MailingTemplateVersion>;
|
|
11
|
+
export declare const storedCategoriesSchema: StoredSchema<TemplateCategory[]>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storedCategoriesSchema = exports.storedVersionRowSchema = exports.storedChangesSchema = exports.storedVariablesSchema = exports.storedContentSchema = void 0;
|
|
4
|
+
exports.parseStored = parseStored;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
function parseStored(text, schema, what) {
|
|
7
|
+
const value = JSON.parse(text);
|
|
8
|
+
const read = schema.safeParse(value);
|
|
9
|
+
if (!read.success)
|
|
10
|
+
throw new TypeError(`expected ${what}`);
|
|
11
|
+
return read.data;
|
|
12
|
+
}
|
|
13
|
+
function oneOf(members) {
|
|
14
|
+
return zod_1.z
|
|
15
|
+
.string()
|
|
16
|
+
.refine((value) => Object.hasOwn(members, value));
|
|
17
|
+
}
|
|
18
|
+
const conditionOperators = {
|
|
19
|
+
truthy: true,
|
|
20
|
+
falsy: true,
|
|
21
|
+
eq: true,
|
|
22
|
+
ne: true,
|
|
23
|
+
gt: true,
|
|
24
|
+
lt: true,
|
|
25
|
+
};
|
|
26
|
+
const textAligns = {
|
|
27
|
+
left: true,
|
|
28
|
+
center: true,
|
|
29
|
+
right: true,
|
|
30
|
+
};
|
|
31
|
+
const variableTypes = {
|
|
32
|
+
string: true,
|
|
33
|
+
text: true,
|
|
34
|
+
number: true,
|
|
35
|
+
money: true,
|
|
36
|
+
date: true,
|
|
37
|
+
url: true,
|
|
38
|
+
boolean: true,
|
|
39
|
+
array: true,
|
|
40
|
+
};
|
|
41
|
+
const blockTypes = {
|
|
42
|
+
hero: true,
|
|
43
|
+
heading: true,
|
|
44
|
+
paragraph: true,
|
|
45
|
+
code: true,
|
|
46
|
+
list: true,
|
|
47
|
+
total: true,
|
|
48
|
+
button: true,
|
|
49
|
+
if: true,
|
|
50
|
+
divider: true,
|
|
51
|
+
footer: true,
|
|
52
|
+
};
|
|
53
|
+
const changeKinds = {
|
|
54
|
+
locale_added: true,
|
|
55
|
+
locale_removed: true,
|
|
56
|
+
subject: true,
|
|
57
|
+
preheader: true,
|
|
58
|
+
block_added: true,
|
|
59
|
+
block_removed: true,
|
|
60
|
+
block_changed: true,
|
|
61
|
+
blocks_reordered: true,
|
|
62
|
+
variable_added: true,
|
|
63
|
+
variable_removed: true,
|
|
64
|
+
variable_changed: true,
|
|
65
|
+
};
|
|
66
|
+
const storedConditionSchema = zod_1.z
|
|
67
|
+
.object({
|
|
68
|
+
path: zod_1.z.string(),
|
|
69
|
+
operator: oneOf(conditionOperators),
|
|
70
|
+
value: zod_1.z.string(),
|
|
71
|
+
})
|
|
72
|
+
.passthrough();
|
|
73
|
+
const align = oneOf(textAligns);
|
|
74
|
+
const base = { id: zod_1.z.string(), visibleIf: storedConditionSchema.nullable() };
|
|
75
|
+
const storedBlockSchema = zod_1.z.lazy(() => storedBlockUnion);
|
|
76
|
+
const storedBlockUnion = zod_1.z.discriminatedUnion("type", [
|
|
77
|
+
zod_1.z
|
|
78
|
+
.object({
|
|
79
|
+
...base,
|
|
80
|
+
type: zod_1.z.literal("hero"),
|
|
81
|
+
imageUrl: zod_1.z.string(),
|
|
82
|
+
alt: zod_1.z.string(),
|
|
83
|
+
})
|
|
84
|
+
.passthrough(),
|
|
85
|
+
zod_1.z
|
|
86
|
+
.object({
|
|
87
|
+
...base,
|
|
88
|
+
type: zod_1.z.literal("heading"),
|
|
89
|
+
text: zod_1.z.string(),
|
|
90
|
+
align,
|
|
91
|
+
size: zod_1.z.number(),
|
|
92
|
+
})
|
|
93
|
+
.passthrough(),
|
|
94
|
+
zod_1.z
|
|
95
|
+
.object({
|
|
96
|
+
...base,
|
|
97
|
+
type: zod_1.z.literal("paragraph"),
|
|
98
|
+
text: zod_1.z.string(),
|
|
99
|
+
align,
|
|
100
|
+
})
|
|
101
|
+
.passthrough(),
|
|
102
|
+
zod_1.z
|
|
103
|
+
.object({ ...base, type: zod_1.z.literal("code"), text: zod_1.z.string() })
|
|
104
|
+
.passthrough(),
|
|
105
|
+
zod_1.z
|
|
106
|
+
.object({
|
|
107
|
+
...base,
|
|
108
|
+
type: zod_1.z.literal("list"),
|
|
109
|
+
source: zod_1.z.string(),
|
|
110
|
+
labelPath: zod_1.z.string(),
|
|
111
|
+
valuePath: zod_1.z.string(),
|
|
112
|
+
})
|
|
113
|
+
.passthrough(),
|
|
114
|
+
zod_1.z
|
|
115
|
+
.object({
|
|
116
|
+
...base,
|
|
117
|
+
type: zod_1.z.literal("total"),
|
|
118
|
+
label: zod_1.z.string(),
|
|
119
|
+
value: zod_1.z.string(),
|
|
120
|
+
})
|
|
121
|
+
.passthrough(),
|
|
122
|
+
zod_1.z
|
|
123
|
+
.object({
|
|
124
|
+
...base,
|
|
125
|
+
type: zod_1.z.literal("button"),
|
|
126
|
+
text: zod_1.z.string(),
|
|
127
|
+
href: zod_1.z.string(),
|
|
128
|
+
align,
|
|
129
|
+
})
|
|
130
|
+
.passthrough(),
|
|
131
|
+
zod_1.z
|
|
132
|
+
.object({
|
|
133
|
+
...base,
|
|
134
|
+
type: zod_1.z.literal("if"),
|
|
135
|
+
condition: storedConditionSchema,
|
|
136
|
+
children: zod_1.z.array(storedBlockSchema),
|
|
137
|
+
elseChildren: zod_1.z.array(storedBlockSchema).nullable(),
|
|
138
|
+
})
|
|
139
|
+
.passthrough(),
|
|
140
|
+
zod_1.z.object({ ...base, type: zod_1.z.literal("divider") }).passthrough(),
|
|
141
|
+
zod_1.z
|
|
142
|
+
.object({
|
|
143
|
+
...base,
|
|
144
|
+
type: zod_1.z.literal("footer"),
|
|
145
|
+
text: zod_1.z.string(),
|
|
146
|
+
unsubscribeLabel: zod_1.z.string(),
|
|
147
|
+
preferencesLabel: zod_1.z.string(),
|
|
148
|
+
})
|
|
149
|
+
.passthrough(),
|
|
150
|
+
]);
|
|
151
|
+
exports.storedContentSchema = zod_1.z
|
|
152
|
+
.object({
|
|
153
|
+
locales: zod_1.z.record(zod_1.z
|
|
154
|
+
.object({
|
|
155
|
+
subject: zod_1.z.string(),
|
|
156
|
+
preheader: zod_1.z.string(),
|
|
157
|
+
blocks: zod_1.z.array(storedBlockSchema),
|
|
158
|
+
})
|
|
159
|
+
.passthrough()),
|
|
160
|
+
})
|
|
161
|
+
.passthrough();
|
|
162
|
+
exports.storedVariablesSchema = zod_1.z.array(zod_1.z
|
|
163
|
+
.object({
|
|
164
|
+
path: zod_1.z.string(),
|
|
165
|
+
type: oneOf(variableTypes),
|
|
166
|
+
required: zod_1.z.boolean(),
|
|
167
|
+
})
|
|
168
|
+
.passthrough());
|
|
169
|
+
exports.storedChangesSchema = zod_1.z.array(zod_1.z
|
|
170
|
+
.object({
|
|
171
|
+
locale: zod_1.z.string(),
|
|
172
|
+
kind: oneOf(changeKinds),
|
|
173
|
+
blockId: zod_1.z.string().optional(),
|
|
174
|
+
blockType: oneOf(blockTypes).optional(),
|
|
175
|
+
variable: zod_1.z.string().optional(),
|
|
176
|
+
})
|
|
177
|
+
.passthrough());
|
|
178
|
+
exports.storedVersionRowSchema = zod_1.z
|
|
179
|
+
.object({
|
|
180
|
+
_id: zod_1.z.string(),
|
|
181
|
+
templateId: zod_1.z.string(),
|
|
182
|
+
version: zod_1.z.number(),
|
|
183
|
+
json_content: zod_1.z.string(),
|
|
184
|
+
json_variables: zod_1.z.string(),
|
|
185
|
+
locales: zod_1.z.string(),
|
|
186
|
+
publishedAt: zod_1.z.string().transform((at) => new Date(at)),
|
|
187
|
+
publishedBy: zod_1.z.string(),
|
|
188
|
+
json_changes: zod_1.z.string(),
|
|
189
|
+
})
|
|
190
|
+
.passthrough();
|
|
191
|
+
exports.storedCategoriesSchema = zod_1.z.array(zod_1.z
|
|
192
|
+
.object({
|
|
193
|
+
id: zod_1.z.string(),
|
|
194
|
+
label: zod_1.z.record(zod_1.z.string()),
|
|
195
|
+
icon: zod_1.z.string(),
|
|
196
|
+
})
|
|
197
|
+
.passthrough());
|
|
198
|
+
//# sourceMappingURL=stored.schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stored.schema.js","sourceRoot":"","sources":["../../src/validation/stored.schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ export interface EditorContext {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const EDITOR_KEY: InjectionKey<EditorContext> = Symbol('dms-mailing-editor')
|
|
24
|
-
const MISSING_CONTEXT = 'useEditorContext() must be called inside
|
|
24
|
+
const MISSING_CONTEXT = 'useEditorContext() must be called inside MailingTemplateEditor'
|
|
25
25
|
|
|
26
26
|
export function provideEditorContext(context: EditorContext): void {
|
|
27
27
|
provide(EDITOR_KEY, context)
|
|
@@ -74,6 +74,11 @@ function backendSourceFile(id: string): string | undefined {
|
|
|
74
74
|
: undefined
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/** `path` with `/` separators, the form Vite gives an importer, so a boundary error names both paths alike on every OS. */
|
|
78
|
+
function forwardSlashes(path: string): string {
|
|
79
|
+
return path.split(sep).join('/')
|
|
80
|
+
}
|
|
81
|
+
|
|
77
82
|
/**
|
|
78
83
|
* Fails the build and the dev server when a module of the frontend resolves to
|
|
79
84
|
* a file under the `src` of the backend package: the browser reaches the
|
|
@@ -113,9 +118,9 @@ function boundaryCheck(): VitePlugin {
|
|
|
113
118
|
const from =
|
|
114
119
|
importer === undefined
|
|
115
120
|
? 'an entry point'
|
|
116
|
-
: importer.replace(QUERY_OR_HASH, '')
|
|
121
|
+
: forwardSlashes(importer.replace(QUERY_OR_HASH, ''))
|
|
117
122
|
return this.error(
|
|
118
|
-
`Backend boundary: ${from} imports ${file}, which is under the src of ${BACKEND_PACKAGE}. The frontend reaches the backend only through its HTTP interface.`,
|
|
123
|
+
`Backend boundary: ${from} imports ${forwardSlashes(file)}, which is under the src of ${BACKEND_PACKAGE}. The frontend reaches the backend only through its HTTP interface.`,
|
|
119
124
|
)
|
|
120
125
|
},
|
|
121
126
|
}
|
|
@@ -8,17 +8,14 @@ interface VueModule {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const COMPONENT_PREFIX = 'Mailing'
|
|
11
|
-
const BLOCKS_DIRECTORY = '/components/blocks/'
|
|
12
|
-
const BLOCK_NAME_PREFIX = 'Block'
|
|
13
11
|
|
|
14
12
|
const components = import.meta.glob<VueModule>('./app/components/**/*.vue')
|
|
15
13
|
|
|
16
14
|
function componentName(path: string): string {
|
|
17
|
-
|
|
15
|
+
return path
|
|
18
16
|
.split('/')
|
|
19
17
|
.at(-1)!
|
|
20
18
|
.replace(/\.vue$/, '')
|
|
21
|
-
return path.includes(BLOCKS_DIRECTORY) ? `${BLOCK_NAME_PREFIX}${base}` : base
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
const frontendModule: DmsFrontendModule = {
|
|
@@ -9,7 +9,6 @@ export default [
|
|
|
9
9
|
{
|
|
10
10
|
files: ['**/*.ts', '**/*.vue'],
|
|
11
11
|
languageOptions: { parserOptions: { parser: ts.parser } },
|
|
12
|
-
rules: { 'vue/multi-word-component-names': 'off' },
|
|
13
12
|
},
|
|
14
13
|
{ files: ['**/*.ts'], languageOptions: { parser: ts.parser } },
|
|
15
14
|
{
|
|
@@ -21,6 +20,15 @@ export default [
|
|
|
21
20
|
'antelopejs/no-typeof-function-only-test': 'error',
|
|
22
21
|
'antelopejs/no-self-import-in-tests': 'error',
|
|
23
22
|
'anti-slop/no-module-mocking': 'error',
|
|
23
|
+
'no-restricted-syntax': [
|
|
24
|
+
'error',
|
|
25
|
+
{
|
|
26
|
+
selector:
|
|
27
|
+
'CallExpression:matches([callee.name=/^(it|test)$/], [callee.object.name=/^(it|test)$/], [callee.callee.object.name=/^(it|test)$/]) ImportExpression',
|
|
28
|
+
message:
|
|
29
|
+
'Import the module under test statically at the top of the file: a dynamic import inside a test body counts the module load in the test timeout.',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
24
32
|
},
|
|
25
33
|
},
|
|
26
34
|
]
|
|
@@ -22,8 +22,8 @@ importers:
|
|
|
22
22
|
version: 3.5.42(typescript@5.9.3)
|
|
23
23
|
devDependencies:
|
|
24
24
|
'@antelopejs/tooling-configs':
|
|
25
|
-
specifier:
|
|
26
|
-
version: 0.
|
|
25
|
+
specifier: '>=0.7.1 <0.8.0'
|
|
26
|
+
version: 0.7.1
|
|
27
27
|
'@nuxt/ui':
|
|
28
28
|
specifier: 4.10.0
|
|
29
29
|
version: 4.10.0(9bdbb06d8a0b4accef61070adc217622)
|
|
@@ -70,8 +70,8 @@ packages:
|
|
|
70
70
|
resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==}
|
|
71
71
|
engines: {node: '>=10'}
|
|
72
72
|
|
|
73
|
-
'@antelopejs/tooling-configs@0.
|
|
74
|
-
resolution: {integrity: sha512-
|
|
73
|
+
'@antelopejs/tooling-configs@0.7.1':
|
|
74
|
+
resolution: {integrity: sha512-X/mr/nQEgmFI2dMr3ThMS7HcPaU1amsTU/RNfEnQv46+l7au8cv7unpypCZ0BggnfJHjpk2QG2CTOOllpwj3cw==}
|
|
75
75
|
engines: {node: '>=22.18.0'}
|
|
76
76
|
hasBin: true
|
|
77
77
|
peerDependencies:
|
|
@@ -79,7 +79,7 @@ packages:
|
|
|
79
79
|
eslint-plugin-perfectionist: '>=5.0.0'
|
|
80
80
|
knip: '>=6.0.0'
|
|
81
81
|
mongodb-memory-server: '>=10.0.0'
|
|
82
|
-
oxfmt: ^0.66.0
|
|
82
|
+
oxfmt: ^0.66.0 || ^0.77.0
|
|
83
83
|
oxlint: 1.81.0
|
|
84
84
|
pixelmatch: '>=7.0.0'
|
|
85
85
|
playwright-core: '>=1.56.0'
|
|
@@ -1496,6 +1496,10 @@ packages:
|
|
|
1496
1496
|
resolution: {integrity: sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==}
|
|
1497
1497
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
|
1498
1498
|
|
|
1499
|
+
'@typescript/typescript6@6.0.2':
|
|
1500
|
+
resolution: {integrity: sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w==}
|
|
1501
|
+
hasBin: true
|
|
1502
|
+
|
|
1499
1503
|
'@unhead/vue@2.1.17':
|
|
1500
1504
|
resolution: {integrity: sha512-pnC8x9HLV3qQXdvWfylUEU25uhfCAy3ly9nmpQz84j9py818DRfU8jOsQ5wjdWtxyU1vX/fW2udfm4jtxUK8Bg==}
|
|
1501
1505
|
peerDependencies:
|
|
@@ -2967,6 +2971,11 @@ packages:
|
|
|
2967
2971
|
engines: {node: '>=14.17'}
|
|
2968
2972
|
hasBin: true
|
|
2969
2973
|
|
|
2974
|
+
typescript@6.0.3:
|
|
2975
|
+
resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
|
|
2976
|
+
engines: {node: '>=14.17'}
|
|
2977
|
+
hasBin: true
|
|
2978
|
+
|
|
2970
2979
|
ufo@1.6.4:
|
|
2971
2980
|
resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}
|
|
2972
2981
|
|
|
@@ -3390,11 +3399,13 @@ snapshots:
|
|
|
3390
3399
|
|
|
3391
3400
|
'@alloc/quick-lru@5.3.0': {}
|
|
3392
3401
|
|
|
3393
|
-
'@antelopejs/tooling-configs@0.
|
|
3402
|
+
'@antelopejs/tooling-configs@0.7.1':
|
|
3394
3403
|
dependencies:
|
|
3395
3404
|
'@oxlint/plugins': 1.81.0
|
|
3405
|
+
'@typescript/typescript6': 6.0.2
|
|
3396
3406
|
dts-bundle-generator: 9.5.1
|
|
3397
|
-
|
|
3407
|
+
minimatch: 10.2.6
|
|
3408
|
+
semver: 7.8.5
|
|
3398
3409
|
yaml: 2.9.1
|
|
3399
3410
|
|
|
3400
3411
|
'@antfu/install-pkg@2.0.1':
|
|
@@ -4667,6 +4678,10 @@ snapshots:
|
|
|
4667
4678
|
'@typescript-eslint/types': 8.70.0
|
|
4668
4679
|
eslint-visitor-keys: 5.0.1
|
|
4669
4680
|
|
|
4681
|
+
'@typescript/typescript6@6.0.2':
|
|
4682
|
+
dependencies:
|
|
4683
|
+
'@typescript/old': typescript@6.0.3
|
|
4684
|
+
|
|
4670
4685
|
'@unhead/vue@2.1.17(vue@3.5.42(typescript@5.9.3))':
|
|
4671
4686
|
dependencies:
|
|
4672
4687
|
hookable: 6.1.1
|
|
@@ -6170,6 +6185,8 @@ snapshots:
|
|
|
6170
6185
|
|
|
6171
6186
|
typescript@5.9.3: {}
|
|
6172
6187
|
|
|
6188
|
+
typescript@6.0.3: {}
|
|
6189
|
+
|
|
6173
6190
|
ufo@1.6.4: {}
|
|
6174
6191
|
|
|
6175
6192
|
uncrypto@0.1.3: {}
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
writeFileSync,
|
|
8
8
|
} from 'node:fs'
|
|
9
9
|
import { tmpdir } from 'node:os'
|
|
10
|
-
import { dirname, join } from 'node:path'
|
|
11
|
-
import { build as viteBuild, type Plugin } from 'vite'
|
|
10
|
+
import { dirname, join } from 'node:path/posix'
|
|
11
|
+
import { normalizePath, build as viteBuild, type Plugin } from 'vite'
|
|
12
12
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
13
13
|
import { backendBoundary } from '../build/backend-boundary'
|
|
14
14
|
|
|
@@ -22,8 +22,8 @@ function write(file: string, text: string): void {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
beforeAll(() => {
|
|
25
|
-
repository =
|
|
26
|
-
mkdtempSync(
|
|
25
|
+
repository = normalizePath(
|
|
26
|
+
realpathSync(mkdtempSync(`${tmpdir()}/dms-mailing-boundary-`)),
|
|
27
27
|
)
|
|
28
28
|
const backend = join(repository, 'packages/dms-mailing')
|
|
29
29
|
frontend = join(backend, 'frontend-vue')
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// @vitest-environment node
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
3
|
import type { VNode } from 'vue'
|
|
4
|
+
import CategoryLabel from '../app/components/CategoryLabel.vue'
|
|
5
|
+
import setup, {
|
|
6
|
+
renderCategory,
|
|
7
|
+
renderLocaleChips,
|
|
8
|
+
} from '../app/plugins/column-displays'
|
|
4
9
|
|
|
5
10
|
interface RegisteredType {
|
|
6
11
|
id: string
|
|
@@ -11,9 +16,12 @@ type PluginSetup = () => void
|
|
|
11
16
|
|
|
12
17
|
const registered: RegisteredType[] = []
|
|
13
18
|
|
|
19
|
+
vi.hoisted(() => {
|
|
20
|
+
vi.stubGlobal('defineDmsPlugin', (pluginSetup: PluginSetup) => pluginSetup)
|
|
21
|
+
})
|
|
22
|
+
|
|
14
23
|
beforeEach(() => {
|
|
15
24
|
registered.length = 0
|
|
16
|
-
vi.stubGlobal('defineDmsPlugin', (setup: PluginSetup) => setup)
|
|
17
25
|
vi.stubGlobal('useDataTypes', () => ({
|
|
18
26
|
registerDataType: (type: RegisteredType) => registered.push(type),
|
|
19
27
|
}))
|
|
@@ -24,7 +32,6 @@ beforeEach(() => {
|
|
|
24
32
|
|
|
25
33
|
afterEach(() => {
|
|
26
34
|
vi.unstubAllGlobals()
|
|
27
|
-
vi.resetModules()
|
|
28
35
|
})
|
|
29
36
|
|
|
30
37
|
function texts(node: VNode): string[] {
|
|
@@ -36,8 +43,7 @@ function texts(node: VNode): string[] {
|
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
describe('column displays plugin', () => {
|
|
39
|
-
it('registers the locale chips and category displays without a DOM',
|
|
40
|
-
const { default: setup } = await import('../app/plugins/column-displays')
|
|
46
|
+
it('registers the locale chips and category displays without a DOM', () => {
|
|
41
47
|
;(setup as unknown as PluginSetup)()
|
|
42
48
|
expect(registered.map((type) => type.id)).toEqual([
|
|
43
49
|
'mailing:locale-chips',
|
|
@@ -45,18 +51,14 @@ describe('column displays plugin', () => {
|
|
|
45
51
|
])
|
|
46
52
|
})
|
|
47
53
|
|
|
48
|
-
it('draws a category through its label component',
|
|
49
|
-
const { renderCategory } = await import('../app/plugins/column-displays')
|
|
50
|
-
const { default: CategoryLabel } =
|
|
51
|
-
await import('../app/components/CategoryLabel.vue')
|
|
54
|
+
it('draws a category through its label component', () => {
|
|
52
55
|
const cell = renderCategory('orders')
|
|
53
56
|
expect(cell.type).toBe(CategoryLabel)
|
|
54
57
|
expect(cell.props).toEqual({ value: 'orders' })
|
|
55
58
|
expect(renderCategory(undefined).props).toEqual({ value: null })
|
|
56
59
|
})
|
|
57
60
|
|
|
58
|
-
it('draws the locale chips with the missing workspace ones dashed',
|
|
59
|
-
const { default: setup } = await import('../app/plugins/column-displays')
|
|
61
|
+
it('draws the locale chips with the missing workspace ones dashed', () => {
|
|
60
62
|
;(setup as unknown as PluginSetup)()
|
|
61
63
|
const cell = registered[0]!.formatter.default('en,fr', 'en')
|
|
62
64
|
const chips = cell.children as VNode[]
|
|
@@ -65,8 +67,7 @@ describe('column displays plugin', () => {
|
|
|
65
67
|
expect(String(chips[0]!.props?.class)).not.toContain('border-dashed')
|
|
66
68
|
})
|
|
67
69
|
|
|
68
|
-
it('draws a dash for a row without locale information',
|
|
69
|
-
const { renderLocaleChips } = await import('../app/plugins/column-displays')
|
|
70
|
+
it('draws a dash for a row without locale information', () => {
|
|
70
71
|
expect(texts(renderLocaleChips('', ['en']))).toEqual(['—'])
|
|
71
72
|
expect(texts(renderLocaleChips(undefined, ['en']))).toEqual(['—'])
|
|
72
73
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @vitest-environment jsdom
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
3
|
import { defineComponent, h, provide, ref } from 'vue'
|
|
4
|
-
import FooterBlockView from '../app/components/blocks/
|
|
4
|
+
import FooterBlockView from '../app/components/blocks/BlockFooter.vue'
|
|
5
5
|
import type { FooterBlock } from '../app/types/mailing'
|
|
6
6
|
import { TOKEN_DATA_KEY } from '../app/utils/tokens'
|
|
7
7
|
import type { TokenData } from '../app/utils/tokens'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @vitest-environment node
|
|
2
2
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
3
3
|
import type { Component } from 'vue'
|
|
4
|
+
import setup from '../app/plugins/template-gallery-display'
|
|
4
5
|
|
|
5
6
|
interface DisplayRegistration {
|
|
6
7
|
id: string
|
|
@@ -9,21 +10,21 @@ interface DisplayRegistration {
|
|
|
9
10
|
|
|
10
11
|
type PluginSetup = () => void
|
|
11
12
|
|
|
13
|
+
vi.hoisted(() => {
|
|
14
|
+
vi.stubGlobal('defineDmsPlugin', (pluginSetup: PluginSetup) => pluginSetup)
|
|
15
|
+
})
|
|
16
|
+
|
|
12
17
|
afterEach(() => {
|
|
13
18
|
vi.unstubAllGlobals()
|
|
14
|
-
vi.resetModules()
|
|
15
19
|
})
|
|
16
20
|
|
|
17
21
|
describe('template gallery display plugin', () => {
|
|
18
|
-
it('registers the gallery under the mailing namespace without a DOM',
|
|
22
|
+
it('registers the gallery under the mailing namespace without a DOM', () => {
|
|
19
23
|
const registrations: DisplayRegistration[] = []
|
|
20
|
-
vi.stubGlobal('defineDmsPlugin', (setup: PluginSetup) => setup)
|
|
21
24
|
vi.stubGlobal(
|
|
22
25
|
'registerTableViewDisplay',
|
|
23
26
|
(registration: DisplayRegistration) => registrations.push(registration),
|
|
24
27
|
)
|
|
25
|
-
const { default: setup } =
|
|
26
|
-
await import('../app/plugins/template-gallery-display')
|
|
27
28
|
setup()
|
|
28
29
|
expect(registrations.map((registration) => registration.id)).toEqual([
|
|
29
30
|
'mailing:gallery',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @vitest-environment node
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import { useTemplateDrawer } from '../app/composables/useTemplateDrawer'
|
|
3
4
|
import type { TemplateRow } from '../app/types/mailing'
|
|
4
5
|
|
|
5
6
|
interface OpenCall {
|
|
@@ -53,7 +54,6 @@ beforeEach(() => {
|
|
|
53
54
|
|
|
54
55
|
afterEach(() => {
|
|
55
56
|
vi.unstubAllGlobals()
|
|
56
|
-
vi.resetModules()
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
function row(id: string): TemplateRow {
|
|
@@ -68,9 +68,7 @@ function row(id: string): TemplateRow {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
describe('useTemplateDrawer', () => {
|
|
71
|
-
it('opens the test send with the editor draft and locale',
|
|
72
|
-
const { useTemplateDrawer } =
|
|
73
|
-
await import('../app/composables/useTemplateDrawer')
|
|
71
|
+
it('opens the test send with the editor draft and locale', () => {
|
|
74
72
|
const content = { locales: {} }
|
|
75
73
|
useTemplateDrawer().openTestSend('t1', { locale: 'fr', content })
|
|
76
74
|
expect(modalCalls[0]?.component).toEqual({ name: 'MailingTestSendModal' })
|
|
@@ -82,8 +80,6 @@ describe('useTemplateDrawer', () => {
|
|
|
82
80
|
})
|
|
83
81
|
|
|
84
82
|
it('calls back only when the dialog closes after a change', async () => {
|
|
85
|
-
const { useTemplateDrawer } =
|
|
86
|
-
await import('../app/composables/useTemplateDrawer')
|
|
87
83
|
const onDone = vi.fn()
|
|
88
84
|
useTemplateDrawer().openRealSend('t1', { onDone })
|
|
89
85
|
await Promise.resolve()
|
|
@@ -97,9 +93,7 @@ describe('useTemplateDrawer', () => {
|
|
|
97
93
|
expect(modalCalls[1]?.componentOptions).toEqual({ initialName: 'Refund' })
|
|
98
94
|
})
|
|
99
95
|
|
|
100
|
-
it('opens the details from the right and steps through the rows shown',
|
|
101
|
-
const { useTemplateDrawer } =
|
|
102
|
-
await import('../app/composables/useTemplateDrawer')
|
|
96
|
+
it('opens the details from the right and steps through the rows shown', () => {
|
|
103
97
|
const rows = [row('a'), row('b'), row('c')]
|
|
104
98
|
useTemplateDrawer().openDetails(rows[1]!, { rows })
|
|
105
99
|
const call = drawerCalls[0]!
|
|
@@ -115,9 +109,7 @@ describe('useTemplateDrawer', () => {
|
|
|
115
109
|
expect((options.navigation as Navigation).hasNext).toBe(false)
|
|
116
110
|
})
|
|
117
111
|
|
|
118
|
-
it('opens the details of a bare id without navigation',
|
|
119
|
-
const { useTemplateDrawer } =
|
|
120
|
-
await import('../app/composables/useTemplateDrawer')
|
|
112
|
+
it('opens the details of a bare id without navigation', () => {
|
|
121
113
|
useTemplateDrawer().openDetails('x')
|
|
122
114
|
expect(drawerCalls[0]?.componentOptions.templateId).toBe('x')
|
|
123
115
|
expect(drawerCalls[0]?.componentOptions.navigation).toBeUndefined()
|