@antelopejs/dms-mailing 0.3.3 → 0.4.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 +232 -22
- package/dist/automation/email-event-trigger.js +2 -2
- package/dist/automation/email-event-trigger.js.map +1 -1
- package/dist/automation/send-template-action.js +2 -2
- package/dist/automation/send-template-action.js.map +1 -1
- package/dist/config.js +3 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts +10 -1
- package/dist/constants.js +15 -3
- package/dist/constants.js.map +1 -1
- package/dist/crons/attention.d.ts +3 -0
- package/dist/crons/attention.js +19 -0
- package/dist/crons/attention.js.map +1 -0
- package/dist/crons/index.d.ts +2 -0
- package/dist/crons/index.js +2 -0
- package/dist/crons/index.js.map +1 -1
- package/dist/crons/jobs.d.ts +12 -0
- package/dist/crons/jobs.js +27 -0
- package/dist/crons/jobs.js.map +1 -0
- package/dist/crons/retention.d.ts +2 -4
- package/dist/crons/retention.js +7 -22
- package/dist/crons/retention.js.map +1 -1
- package/dist/data/displays.d.ts +5 -0
- package/dist/data/displays.js +23 -0
- package/dist/data/displays.js.map +1 -0
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/index.js.map +1 -1
- package/dist/data/locale-fallback.d.ts +3 -0
- package/dist/data/locale-fallback.js +20 -0
- package/dist/data/locale-fallback.js.map +1 -0
- package/dist/data/read-only-routes.d.ts +7 -0
- package/dist/data/read-only-routes.js +13 -0
- package/dist/data/read-only-routes.js.map +1 -0
- package/dist/data/sends-table.d.ts +19 -5
- package/dist/data/sends-table.js +185 -17
- package/dist/data/sends-table.js.map +1 -1
- package/dist/data/suppressions-table.d.ts +24 -0
- package/dist/data/suppressions-table.js +120 -0
- package/dist/data/suppressions-table.js.map +1 -0
- package/dist/data/templates-table.d.ts +20 -2
- package/dist/data/templates-table.js +188 -31
- package/dist/data/templates-table.js.map +1 -1
- package/dist/data-types/categories-type.d.ts +11 -13
- package/dist/data-types/categories-type.js +3 -3
- package/dist/data-types/categories-type.js.map +1 -1
- package/dist/data-types/category-type.js +1 -1
- package/dist/data-types/category-type.js.map +1 -1
- package/dist/db/models/index.d.ts +3 -0
- package/dist/db/models/index.js +3 -0
- package/dist/db/models/index.js.map +1 -1
- package/dist/db/models/sends.model.d.ts +12 -1
- package/dist/db/models/sends.model.js +64 -0
- package/dist/db/models/sends.model.js.map +1 -1
- package/dist/db/models/settings.model.d.ts +0 -1
- package/dist/db/models/settings.model.js +0 -7
- package/dist/db/models/settings.model.js.map +1 -1
- package/dist/db/models/suppressions.model.d.ts +28 -0
- package/dist/db/models/suppressions.model.js +46 -0
- package/dist/db/models/suppressions.model.js.map +1 -0
- package/dist/db/models/template-versions.model.d.ts +24 -0
- package/dist/db/models/template-versions.model.js +17 -0
- package/dist/db/models/template-versions.model.js.map +1 -0
- package/dist/db/models/templates.model.d.ts +2 -0
- package/dist/db/models/templates.model.js +3 -0
- package/dist/db/models/templates.model.js.map +1 -1
- package/dist/db/models/webhook-status.model.d.ts +24 -0
- package/dist/db/models/webhook-status.model.js +21 -0
- package/dist/db/models/webhook-status.model.js.map +1 -0
- package/dist/db/tables/index.d.ts +3 -0
- package/dist/db/tables/index.js +3 -0
- package/dist/db/tables/index.js.map +1 -1
- package/dist/db/tables/send-events.table.d.ts +2 -2
- package/dist/db/tables/send-events.table.js.map +1 -1
- package/dist/db/tables/sends.table.d.ts +10 -2
- package/dist/db/tables/sends.table.js +34 -1
- package/dist/db/tables/sends.table.js.map +1 -1
- package/dist/db/tables/suppressions.table.d.ts +12 -0
- package/dist/db/tables/suppressions.table.js +53 -0
- package/dist/db/tables/suppressions.table.js.map +1 -0
- package/dist/db/tables/template-versions.table.d.ts +13 -0
- package/dist/db/tables/template-versions.table.js +59 -0
- package/dist/db/tables/template-versions.table.js.map +1 -0
- package/dist/db/tables/templates.table.d.ts +11 -0
- package/dist/db/tables/templates.table.js +45 -0
- package/dist/db/tables/templates.table.js.map +1 -1
- package/dist/db/tables/webhook-status.table.d.ts +14 -0
- package/dist/db/tables/webhook-status.table.js +58 -0
- package/dist/db/tables/webhook-status.table.js.map +1 -0
- package/dist/engine/changes.d.ts +12 -0
- package/dist/engine/changes.js +107 -0
- package/dist/engine/changes.js.map +1 -0
- package/dist/engine/conditions.js +0 -2
- package/dist/engine/conditions.js.map +1 -1
- package/dist/engine/coverage.d.ts +1 -0
- package/dist/engine/coverage.js +6 -2
- package/dist/engine/coverage.js.map +1 -1
- package/dist/engine/fallback-html.d.ts +1 -1
- package/dist/engine/fallback-html.js +51 -34
- package/dist/engine/fallback-html.js.map +1 -1
- package/dist/engine/index.d.ts +3 -0
- package/dist/engine/index.js +3 -0
- package/dist/engine/index.js.map +1 -1
- package/dist/engine/plain-text.d.ts +3 -0
- package/dist/engine/plain-text.js +60 -0
- package/dist/engine/plain-text.js.map +1 -0
- package/dist/engine/resolve.d.ts +2 -1
- package/dist/engine/resolve.js +17 -9
- package/dist/engine/resolve.js.map +1 -1
- package/dist/engine/system-variables.d.ts +10 -0
- package/dist/engine/system-variables.js +70 -0
- package/dist/engine/system-variables.js.map +1 -0
- package/dist/engine/tokens.d.ts +2 -1
- package/dist/engine/tokens.js +6 -2
- package/dist/engine/tokens.js.map +1 -1
- package/dist/hooks/tenant-export.js +13 -1
- package/dist/hooks/tenant-export.js.map +1 -1
- package/dist/implementations/dms-mailing/index.d.ts +1 -1
- package/dist/implementations/dms-mailing/index.js +2 -2
- package/dist/implementations/dms-mailing/index.js.map +1 -1
- package/dist/index.js +13 -11
- package/dist/index.js.map +1 -1
- package/dist/pages/editor.js +9 -2
- package/dist/pages/editor.js.map +1 -1
- package/dist/pages/index.d.ts +1 -0
- package/dist/pages/index.js +1 -0
- package/dist/pages/index.js.map +1 -1
- package/dist/pages/module.d.ts +2 -0
- package/dist/pages/module.js +26 -2
- package/dist/pages/module.js.map +1 -1
- package/dist/pages/overview.d.ts +2 -6
- package/dist/pages/overview.js +109 -52
- package/dist/pages/overview.js.map +1 -1
- package/dist/pages/sends.d.ts +3 -4
- package/dist/pages/sends.js +197 -60
- package/dist/pages/sends.js.map +1 -1
- package/dist/pages/settings/form.js +114 -53
- package/dist/pages/settings/form.js.map +1 -1
- package/dist/pages/settings/page.d.ts +0 -1
- package/dist/pages/settings/page.js +8 -11
- package/dist/pages/settings/page.js.map +1 -1
- package/dist/pages/suppressions.d.ts +9 -0
- package/dist/pages/suppressions.js +151 -0
- package/dist/pages/suppressions.js.map +1 -0
- package/dist/pages/templates.d.ts +0 -1
- package/dist/pages/templates.js +114 -40
- package/dist/pages/templates.js.map +1 -1
- package/dist/permissions.js +2 -2
- package/dist/permissions.js.map +1 -1
- package/dist/quick-actions.js +7 -4
- package/dist/quick-actions.js.map +1 -1
- package/dist/routes/events.d.ts +8 -5
- package/dist/routes/events.js +55 -24
- package/dist/routes/events.js.map +1 -1
- package/dist/routes/index.d.ts +2 -0
- package/dist/routes/index.js +2 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/metrics.d.ts +60 -23
- package/dist/routes/metrics.js +231 -83
- package/dist/routes/metrics.js.map +1 -1
- package/dist/routes/period.d.ts +2 -1
- package/dist/routes/period.js +9 -3
- package/dist/routes/period.js.map +1 -1
- package/dist/routes/sends.d.ts +49 -8
- package/dist/routes/sends.js +239 -24
- package/dist/routes/sends.js.map +1 -1
- package/dist/routes/settings.d.ts +44 -5
- package/dist/routes/settings.js +190 -15
- package/dist/routes/settings.js.map +1 -1
- package/dist/routes/suppressions.d.ts +16 -0
- package/dist/routes/suppressions.js +92 -0
- package/dist/routes/suppressions.js.map +1 -0
- package/dist/routes/template-versions.d.ts +28 -0
- package/dist/routes/template-versions.js +87 -0
- package/dist/routes/template-versions.js.map +1 -0
- package/dist/routes/templates.d.ts +60 -6
- package/dist/routes/templates.js +204 -35
- package/dist/routes/templates.js.map +1 -1
- package/dist/services/attention.d.ts +19 -6
- package/dist/services/attention.js +177 -12
- package/dist/services/attention.js.map +1 -1
- package/dist/services/catalog.d.ts +3 -0
- package/dist/services/catalog.js +25 -0
- package/dist/services/catalog.js.map +1 -0
- package/dist/services/categories.d.ts +8 -32
- package/dist/services/categories.js +14 -25
- package/dist/services/categories.js.map +1 -1
- package/dist/services/checked-send.d.ts +9 -0
- package/dist/services/checked-send.js +54 -0
- package/dist/services/checked-send.js.map +1 -0
- package/dist/services/events.d.ts +5 -0
- package/dist/services/events.js +102 -9
- package/dist/services/events.js.map +1 -1
- package/dist/services/metrics.d.ts +17 -6
- package/dist/services/metrics.js +57 -18
- package/dist/services/metrics.js.map +1 -1
- package/dist/services/notify.d.ts +18 -10
- package/dist/services/notify.js +82 -37
- package/dist/services/notify.js.map +1 -1
- package/dist/services/provider-banner.d.ts +14 -0
- package/dist/services/provider-banner.js +115 -0
- package/dist/services/provider-banner.js.map +1 -0
- package/dist/services/render.js.map +1 -1
- package/dist/services/send-stat-items.d.ts +7 -0
- package/dist/services/send-stat-items.js +127 -0
- package/dist/services/send-stat-items.js.map +1 -0
- package/dist/services/send-stats.d.ts +23 -0
- package/dist/services/send-stats.js +63 -0
- package/dist/services/send-stats.js.map +1 -0
- package/dist/services/send.d.ts +18 -3
- package/dist/services/send.js +81 -17
- package/dist/services/send.js.map +1 -1
- package/dist/services/settings.d.ts +5 -0
- package/dist/services/settings.js +28 -7
- package/dist/services/settings.js.map +1 -1
- package/dist/services/starters.d.ts +15 -0
- package/dist/services/starters.js +264 -0
- package/dist/services/starters.js.map +1 -0
- package/dist/services/suppressions.d.ts +20 -0
- package/dist/services/suppressions.js +53 -0
- package/dist/services/suppressions.js.map +1 -0
- package/dist/services/template-attention.d.ts +4 -0
- package/dist/services/template-attention.js +43 -0
- package/dist/services/template-attention.js.map +1 -0
- package/dist/services/template-stats.d.ts +27 -0
- package/dist/services/template-stats.js +59 -0
- package/dist/services/template-stats.js.map +1 -0
- package/dist/services/templates.d.ts +31 -4
- package/dist/services/templates.js +240 -21
- package/dist/services/templates.js.map +1 -1
- package/dist/services/webhook-status.d.ts +27 -0
- package/dist/services/webhook-status.js +134 -0
- package/dist/services/webhook-status.js.map +1 -0
- package/dist/types/blocks.d.ts +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/sends.d.ts +10 -1
- package/dist/types/sends.js +35 -2
- package/dist/types/sends.js.map +1 -1
- package/dist/types/suppressions.d.ts +9 -0
- package/dist/types/suppressions.js +10 -0
- package/dist/types/suppressions.js.map +1 -0
- package/dist/types/webhook.d.ts +17 -0
- package/dist/types/webhook.js +3 -0
- package/dist/types/webhook.js.map +1 -0
- package/dist/validation/settings.schema.d.ts +144 -9
- package/dist/validation/settings.schema.js +113 -16
- package/dist/validation/settings.schema.js.map +1 -1
- package/dist/validation/templates.schema.d.ts +137 -10
- package/dist/validation/templates.schema.js +28 -2
- package/dist/validation/templates.schema.js.map +1 -1
- package/frontend-vue/app/build/components/FormFieldRow.vue +90 -0
- package/frontend-vue/app/build/components/FormRows.vue +26 -0
- package/frontend-vue/app/build/components/RequiredLegend.vue +11 -0
- package/frontend-vue/app/components/CategoriesInput.vue +323 -77
- package/frontend-vue/app/components/CategoryInput.vue +13 -14
- package/frontend-vue/app/components/CategoryLabel.vue +34 -0
- package/frontend-vue/app/components/DuplicateModal.vue +201 -0
- package/frontend-vue/app/components/Editor.vue +55 -20
- package/frontend-vue/app/components/FixAddressModal.vue +133 -0
- package/frontend-vue/app/components/FunnelCard.vue +146 -43
- package/frontend-vue/app/components/LocaleSelect.vue +98 -0
- package/frontend-vue/app/components/NewTemplateModal.vue +388 -102
- package/frontend-vue/app/components/NewTemplateSourceTile.vue +70 -0
- package/frontend-vue/app/components/OverviewGate.vue +220 -0
- package/frontend-vue/app/components/PageHeader.vue +98 -0
- package/frontend-vue/app/components/RealSendModal.vue +555 -0
- package/frontend-vue/app/components/RecipientsField.vue +41 -0
- package/frontend-vue/app/components/RenderingModal.vue +189 -0
- package/frontend-vue/app/components/RetentionInput.vue +212 -0
- package/frontend-vue/app/components/SendDrawer.vue +542 -209
- package/frontend-vue/app/components/StarterGallery.vue +153 -0
- package/frontend-vue/app/components/SystemVariables.vue +63 -0
- package/frontend-vue/app/components/TemplateCard.vue +218 -57
- package/frontend-vue/app/components/TemplateDrawer.vue +785 -274
- package/frontend-vue/app/components/TemplateGallery.vue +312 -56
- package/frontend-vue/app/components/TemplatePreviewFrame.vue +112 -22
- package/frontend-vue/app/components/TestSendModal.vue +266 -95
- package/frontend-vue/app/components/TokenText.vue +61 -10
- package/frontend-vue/app/components/VariablePath.vue +20 -0
- package/frontend-vue/app/components/VersionHistory.vue +196 -0
- package/frontend-vue/app/components/VersionPreview.vue +164 -0
- package/frontend-vue/app/components/WebhookStatus.vue +130 -0
- package/frontend-vue/app/components/blocks/Button.vue +1 -1
- package/frontend-vue/app/components/blocks/Code.vue +1 -1
- package/frontend-vue/app/components/blocks/Footer.vue +56 -7
- package/frontend-vue/app/components/blocks/Heading.vue +1 -1
- package/frontend-vue/app/components/blocks/Hero.vue +13 -7
- package/frontend-vue/app/components/blocks/List.vue +50 -6
- package/frontend-vue/app/components/blocks/Paragraph.vue +1 -1
- package/frontend-vue/app/components/blocks/Total.vue +3 -3
- package/frontend-vue/app/components/editor/EditorAutocompleteMenu.vue +50 -0
- package/frontend-vue/app/components/editor/EditorBlock.vue +37 -90
- package/frontend-vue/app/components/editor/EditorBlockFields.vue +140 -0
- package/frontend-vue/app/components/editor/EditorBlockInspector.vue +92 -0
- package/frontend-vue/app/components/editor/EditorBlockList.vue +32 -25
- package/frontend-vue/app/components/editor/EditorBlockPicker.vue +58 -0
- package/frontend-vue/app/components/editor/EditorBlockTools.vue +71 -0
- package/frontend-vue/app/components/editor/EditorCanvas.vue +105 -70
- package/frontend-vue/app/components/editor/EditorCompare.vue +211 -0
- package/frontend-vue/app/components/editor/EditorConditionFields.vue +56 -46
- package/frontend-vue/app/components/editor/EditorConditionInspector.vue +54 -0
- package/frontend-vue/app/components/editor/EditorEnvelope.vue +77 -0
- package/frontend-vue/app/components/editor/EditorIfBlock.vue +36 -86
- package/frontend-vue/app/components/editor/EditorInsertPoint.vue +64 -0
- package/frontend-vue/app/components/editor/EditorInspector.vue +80 -0
- package/frontend-vue/app/components/editor/EditorLeftPane.vue +103 -0
- package/frontend-vue/app/components/editor/EditorLifecycle.vue +67 -0
- package/frontend-vue/app/components/editor/EditorLoading.vue +23 -0
- package/frontend-vue/app/components/editor/EditorLocaleSwitch.vue +61 -0
- package/frontend-vue/app/components/editor/EditorMissingLocale.vue +72 -48
- package/frontend-vue/app/components/editor/EditorMissingPolicy.vue +42 -0
- package/frontend-vue/app/components/editor/EditorNotice.vue +127 -0
- package/frontend-vue/app/components/editor/EditorOutline.vue +65 -0
- package/frontend-vue/app/components/editor/EditorPalette.vue +95 -42
- package/frontend-vue/app/components/editor/EditorPaletteGroup.vue +66 -0
- package/frontend-vue/app/components/editor/EditorPublishReview.vue +102 -0
- package/frontend-vue/app/components/editor/EditorSaveState.vue +88 -0
- package/frontend-vue/app/components/editor/EditorShortcutHint.vue +17 -0
- package/frontend-vue/app/components/editor/EditorSimChip.vue +51 -0
- package/frontend-vue/app/components/editor/EditorTemplatePane.vue +131 -0
- package/frontend-vue/app/components/editor/EditorTestDataPane.vue +98 -0
- package/frontend-vue/app/components/editor/EditorTitle.vue +82 -0
- package/frontend-vue/app/components/editor/EditorTokenField.vue +224 -0
- package/frontend-vue/app/components/editor/EditorToolbar.vue +34 -134
- package/frontend-vue/app/components/editor/EditorVariableForm.vue +100 -0
- package/frontend-vue/app/components/editor/EditorVariableRow.vue +87 -0
- package/frontend-vue/app/components/editor/EditorVariablesPane.vue +161 -0
- package/frontend-vue/app/components/editor/EditorViewSwitches.vue +76 -0
- package/frontend-vue/app/components/editor/EditorVisibility.vue +101 -0
- package/frontend-vue/app/components/editor/EditorWorkspace.vue +62 -149
- package/frontend-vue/app/composables/useBlockContext.ts +16 -0
- package/frontend-vue/app/composables/useEditorActions.ts +381 -0
- package/frontend-vue/app/composables/useEditorAnnouncements.ts +51 -0
- package/frontend-vue/app/composables/useEditorContext.ts +30 -23
- package/frontend-vue/app/composables/useEditorSession.ts +299 -0
- package/frontend-vue/app/composables/useEditorShortcuts.ts +81 -0
- package/frontend-vue/app/composables/useLocalizedDefaults.ts +17 -0
- package/frontend-vue/app/composables/useMailingApi.ts +142 -27
- package/frontend-vue/app/composables/useOverviewSetup.ts +13 -0
- package/frontend-vue/app/composables/useReplayToast.ts +72 -0
- package/frontend-vue/app/composables/useTemplateCategories.ts +35 -0
- package/frontend-vue/app/composables/useTemplateDrawer.ts +196 -62
- package/frontend-vue/app/composables/useTemplateEditor.ts +318 -86
- package/frontend-vue/app/emails/EmailMailingTemplate.vue +16 -4
- package/frontend-vue/app/emails/components/MailingBlocks.vue +96 -38
- package/frontend-vue/app/emails/components/MailingTextLines.vue +20 -0
- package/frontend-vue/app/plugins/column-displays.ts +65 -0
- package/frontend-vue/app/plugins/{template-gallery-display.client.ts → template-gallery-display.ts} +1 -1
- package/frontend-vue/app/types/mailing.ts +193 -18
- package/frontend-vue/app/utils/api-error.ts +33 -0
- package/frontend-vue/app/utils/autocomplete.ts +120 -0
- package/frontend-vue/app/utils/blocks/components.ts +10 -10
- package/frontend-vue/app/utils/blocks/dnd.ts +7 -3
- package/frontend-vue/app/utils/blocks/factory.ts +199 -38
- package/frontend-vue/app/utils/blocks/fields.ts +39 -19
- package/frontend-vue/app/utils/blocks/index.ts +1 -0
- package/frontend-vue/app/utils/blocks/outline.ts +91 -0
- package/frontend-vue/app/utils/blocks/tree.ts +114 -2
- package/frontend-vue/app/utils/categories.ts +201 -15
- package/frontend-vue/app/utils/changes.ts +152 -0
- package/frontend-vue/app/utils/conditions.ts +25 -19
- package/frontend-vue/app/utils/editor-checks.ts +266 -0
- package/frontend-vue/app/utils/editor-route.ts +43 -4
- package/frontend-vue/app/utils/funnel.ts +74 -0
- package/frontend-vue/app/utils/gallery.ts +179 -1
- package/frontend-vue/app/utils/history.ts +66 -0
- package/frontend-vue/app/utils/lifecycle.ts +185 -0
- package/frontend-vue/app/utils/locales.ts +107 -2
- package/frontend-vue/app/utils/overview-setup.ts +83 -0
- package/frontend-vue/app/utils/pages.ts +5 -0
- package/frontend-vue/app/utils/paths.ts +51 -15
- package/frontend-vue/app/utils/period.ts +62 -22
- package/frontend-vue/app/utils/problems.ts +181 -0
- package/frontend-vue/app/utils/recipients.ts +49 -0
- package/frontend-vue/app/utils/rendering-title.ts +23 -0
- package/frontend-vue/app/utils/send-actions.ts +207 -0
- package/frontend-vue/app/utils/send-link.ts +28 -0
- package/frontend-vue/app/utils/send-snippet.ts +97 -0
- package/frontend-vue/app/utils/send-stats.ts +24 -0
- package/frontend-vue/app/utils/send-values.ts +156 -0
- package/frontend-vue/app/utils/shortcuts.ts +113 -0
- package/frontend-vue/app/utils/slug.ts +82 -0
- package/frontend-vue/app/utils/starters.ts +23 -0
- package/frontend-vue/app/utils/suppression.ts +112 -0
- package/frontend-vue/app/utils/system-variables.ts +165 -0
- package/frontend-vue/app/utils/template-attention.ts +104 -0
- package/frontend-vue/app/utils/timeline.ts +221 -19
- package/frontend-vue/app/utils/tokens.ts +115 -13
- package/frontend-vue/app/utils/variable-types.ts +23 -0
- package/frontend-vue/app/utils/variables.ts +208 -1
- package/frontend-vue/app/utils/version-history.ts +53 -0
- package/frontend-vue/app/utils/webhook-status.ts +170 -0
- package/frontend-vue/dms.frontend.ts +19 -11
- package/frontend-vue/i18n/locales/mailing-en-GB.json +1173 -161
- package/frontend-vue/i18n/locales/mailing-fr-FR.json +1220 -208
- package/frontend-vue/package.json +4 -1
- package/frontend-vue/pnpm-lock.yaml +46 -161
- package/frontend-vue/tests/api-error.test.ts +27 -0
- package/frontend-vue/tests/autocomplete.test.ts +84 -0
- package/frontend-vue/tests/block-components.test.ts +1 -1
- package/frontend-vue/tests/block-fields.test.ts +12 -2
- package/frontend-vue/tests/blocks-factory.test.ts +46 -0
- package/frontend-vue/tests/blocks-outline.test.ts +102 -0
- package/frontend-vue/tests/blocks-tree.test.ts +28 -1
- package/frontend-vue/tests/categories-input.test.ts +139 -0
- package/frontend-vue/tests/categories.test.ts +148 -15
- package/frontend-vue/tests/changes.test.ts +136 -0
- package/frontend-vue/tests/column-displays.test.ts +73 -0
- package/frontend-vue/tests/conditions.test.ts +49 -19
- package/frontend-vue/tests/dnd.test.ts +10 -0
- package/frontend-vue/tests/editor-block-list.test.ts +24 -2
- package/frontend-vue/tests/editor-checks.test.ts +178 -0
- package/frontend-vue/tests/editor-route.test.ts +37 -9
- package/frontend-vue/tests/editor-session.test.ts +206 -0
- package/frontend-vue/tests/footer-block.test.ts +88 -0
- package/frontend-vue/tests/funnel-card.test.ts +116 -0
- package/frontend-vue/tests/funnel.test.ts +81 -0
- package/frontend-vue/tests/gallery.test.ts +124 -2
- package/frontend-vue/tests/helpers/nuxt-globals.ts +232 -0
- package/frontend-vue/tests/history.test.ts +48 -0
- package/frontend-vue/tests/i18n-editor.test.ts +38 -0
- package/frontend-vue/tests/i18n.test.ts +55 -0
- package/frontend-vue/tests/lifecycle.test.ts +145 -0
- package/frontend-vue/tests/locales.test.ts +60 -0
- package/frontend-vue/tests/localized-defaults.test.ts +54 -0
- package/frontend-vue/tests/new-template-modal.test.ts +210 -0
- package/frontend-vue/tests/overview-gate.test.ts +146 -0
- package/frontend-vue/tests/overview-setup.test.ts +78 -0
- package/frontend-vue/tests/paths.test.ts +23 -0
- package/frontend-vue/tests/period.test.ts +59 -10
- package/frontend-vue/tests/problems.test.ts +153 -0
- package/frontend-vue/tests/recipients.test.ts +47 -0
- package/frontend-vue/tests/rendering-title.test.ts +24 -0
- package/frontend-vue/tests/replay-toast.test.ts +67 -0
- package/frontend-vue/tests/retention-input.test.ts +129 -0
- package/frontend-vue/tests/send-actions.test.ts +128 -0
- package/frontend-vue/tests/send-modals.test.ts +415 -0
- package/frontend-vue/tests/send-snippet.test.ts +51 -0
- package/frontend-vue/tests/send-stats.test.ts +12 -0
- package/frontend-vue/tests/send-values.test.ts +119 -0
- package/frontend-vue/tests/shortcuts.test.ts +75 -0
- package/frontend-vue/tests/slug.test.ts +88 -0
- package/frontend-vue/tests/suppression.test.ts +159 -0
- package/frontend-vue/tests/system-variables.test.ts +133 -0
- package/frontend-vue/tests/template-attention.test.ts +123 -0
- package/frontend-vue/tests/template-drawer.test.ts +449 -0
- package/frontend-vue/tests/template-editor.test.ts +218 -9
- package/frontend-vue/tests/template-gallery-display.test.ts +32 -0
- package/frontend-vue/tests/template-gallery.test.ts +370 -0
- package/frontend-vue/tests/template-overlays.test.ts +125 -0
- package/frontend-vue/tests/timeline.test.ts +175 -20
- package/frontend-vue/tests/tokens.test.ts +79 -1
- package/frontend-vue/tests/variable-path.test.ts +22 -0
- package/frontend-vue/tests/variable-types.test.ts +20 -0
- package/frontend-vue/tests/variables.test.ts +90 -2
- package/frontend-vue/tests/version-history.test.ts +41 -0
- package/frontend-vue/tests/webhook-status.test.ts +108 -0
- package/package.json +11 -9
- package/src/automation/email-event-trigger.ts +3 -3
- package/src/automation/send-template-action.ts +7 -5
- package/src/config.ts +3 -1
- package/src/constants.ts +18 -2
- package/src/crons/attention.ts +21 -0
- package/src/crons/index.ts +2 -0
- package/src/crons/jobs.ts +35 -0
- package/src/crons/retention.ts +7 -22
- package/src/data/displays.ts +18 -0
- package/src/data/index.ts +1 -0
- package/src/data/locale-fallback.ts +26 -0
- package/src/data/read-only-routes.ts +14 -0
- package/src/data/sends-table.ts +204 -19
- package/src/data/suppressions-table.ts +127 -0
- package/src/data/templates-table.ts +295 -63
- package/src/data-types/categories-type.ts +4 -5
- package/src/data-types/category-type.ts +1 -1
- package/src/db/models/index.ts +3 -0
- package/src/db/models/sends.model.ts +102 -1
- package/src/db/models/settings.model.ts +2 -12
- package/src/db/models/suppressions.model.ts +53 -0
- package/src/db/models/template-versions.model.ts +23 -0
- package/src/db/models/templates.model.ts +17 -0
- package/src/db/models/webhook-status.model.ts +25 -0
- package/src/db/tables/index.ts +3 -0
- package/src/db/tables/send-events.table.ts +6 -2
- package/src/db/tables/sends.table.ts +37 -2
- package/src/db/tables/suppressions.table.ts +46 -0
- package/src/db/tables/template-versions.table.ts +44 -0
- package/src/db/tables/templates.table.ts +67 -5
- package/src/db/tables/webhook-status.table.ts +44 -0
- package/src/engine/changes.ts +198 -0
- package/src/engine/conditions.ts +1 -7
- package/src/engine/coverage.ts +7 -2
- package/src/engine/fallback-html.ts +80 -42
- package/src/engine/index.ts +3 -0
- package/src/engine/plain-text.ts +86 -0
- package/src/engine/resolve.ts +49 -15
- package/src/engine/system-variables.ts +124 -0
- package/src/engine/tokens.ts +13 -1
- package/src/hooks/tenant-export.ts +21 -2
- package/src/implementations/dms-mailing/index.ts +1 -1
- package/src/index.ts +29 -13
- package/src/pages/editor.ts +13 -2
- package/src/pages/index.ts +6 -3
- package/src/pages/module.ts +31 -2
- package/src/pages/overview.ts +187 -128
- package/src/pages/sends.ts +271 -112
- package/src/pages/settings/form.ts +144 -54
- package/src/pages/settings/page.ts +9 -17
- package/src/pages/suppressions.ts +157 -0
- package/src/pages/templates.ts +139 -42
- package/src/permissions.ts +6 -4
- package/src/quick-actions.ts +12 -5
- package/src/routes/events.ts +110 -33
- package/src/routes/index.ts +2 -0
- package/src/routes/metrics.ts +348 -98
- package/src/routes/period.ts +23 -6
- package/src/routes/sends.ts +413 -41
- package/src/routes/settings.ts +291 -26
- package/src/routes/suppressions.ts +87 -0
- package/src/routes/template-versions.ts +116 -0
- package/src/routes/templates.ts +334 -48
- package/src/services/attention.ts +283 -30
- package/src/services/catalog.ts +28 -0
- package/src/services/categories.ts +28 -27
- package/src/services/checked-send.ts +123 -0
- package/src/services/events.ts +174 -20
- package/src/services/metrics.ts +137 -28
- package/src/services/notify.ts +126 -44
- package/src/services/provider-banner.ts +165 -0
- package/src/services/render.ts +1 -0
- package/src/services/send-stat-items.ts +160 -0
- package/src/services/send-stats.ts +122 -0
- package/src/services/send.ts +193 -31
- package/src/services/settings.ts +52 -8
- package/src/services/starters.ts +383 -0
- package/src/services/suppressions.ts +116 -0
- package/src/services/template-attention.ts +82 -0
- package/src/services/template-stats.ts +97 -0
- package/src/services/templates.ts +400 -37
- package/src/services/webhook-status.ts +202 -0
- package/src/types/blocks.ts +6 -0
- package/src/types/index.ts +2 -0
- package/src/types/sends.ts +64 -2
- package/src/types/suppressions.ts +27 -0
- package/src/types/webhook.ts +29 -0
- package/src/validation/settings.schema.ts +173 -17
- package/src/validation/templates.schema.ts +53 -1
- package/dist/antelope-modules.d.ts +0 -32
- package/dist/antelope-modules.js +0 -36
- package/dist/antelope-modules.js.map +0 -1
- package/dist/test/antelope.test.d.ts +0 -2
- package/dist/test/antelope.test.js +0 -180
- package/dist/test/antelope.test.js.map +0 -1
- package/dist/test/helpers/http.d.ts +0 -4
- package/dist/test/helpers/http.js +0 -28
- package/dist/test/helpers/http.js.map +0 -1
- package/dist/test/helpers/owner.d.ts +0 -5
- package/dist/test/helpers/owner.js +0 -30
- package/dist/test/helpers/owner.js.map +0 -1
- package/dist/test/integration/events.test.d.ts +0 -1
- package/dist/test/integration/events.test.js +0 -143
- package/dist/test/integration/events.test.js.map +0 -1
- package/dist/test/integration/retention.test.d.ts +0 -1
- package/dist/test/integration/retention.test.js +0 -291
- package/dist/test/integration/retention.test.js.map +0 -1
- package/dist/test/integration/sends.test.d.ts +0 -1
- package/dist/test/integration/sends.test.js +0 -210
- package/dist/test/integration/sends.test.js.map +0 -1
- package/dist/test/integration/settings.test.d.ts +0 -1
- package/dist/test/integration/settings.test.js +0 -137
- package/dist/test/integration/settings.test.js.map +0 -1
- package/dist/test/integration/setup.test.d.ts +0 -1
- package/dist/test/integration/setup.test.js +0 -32
- package/dist/test/integration/setup.test.js.map +0 -1
- package/dist/test/integration/templates.test.d.ts +0 -1
- package/dist/test/integration/templates.test.js +0 -233
- package/dist/test/integration/templates.test.js.map +0 -1
- package/dist/test/integration/tenant-export.test.d.ts +0 -1
- package/dist/test/integration/tenant-export.test.js +0 -85
- package/dist/test/integration/tenant-export.test.js.map +0 -1
- package/dist/test/unit/attention.test.d.ts +0 -1
- package/dist/test/unit/attention.test.js +0 -109
- package/dist/test/unit/attention.test.js.map +0 -1
- package/dist/test/unit/automation.test.d.ts +0 -1
- package/dist/test/unit/automation.test.js +0 -104
- package/dist/test/unit/automation.test.js.map +0 -1
- package/dist/test/unit/categories.test.d.ts +0 -1
- package/dist/test/unit/categories.test.js +0 -38
- package/dist/test/unit/categories.test.js.map +0 -1
- package/dist/test/unit/engine/conditions.test.d.ts +0 -1
- package/dist/test/unit/engine/conditions.test.js +0 -23
- package/dist/test/unit/engine/conditions.test.js.map +0 -1
- package/dist/test/unit/engine/coverage.test.d.ts +0 -1
- package/dist/test/unit/engine/coverage.test.js +0 -106
- package/dist/test/unit/engine/coverage.test.js.map +0 -1
- package/dist/test/unit/engine/fallback-html.test.d.ts +0 -1
- package/dist/test/unit/engine/fallback-html.test.js +0 -78
- package/dist/test/unit/engine/fallback-html.test.js.map +0 -1
- package/dist/test/unit/engine/paths.test.d.ts +0 -1
- package/dist/test/unit/engine/paths.test.js +0 -33
- package/dist/test/unit/engine/paths.test.js.map +0 -1
- package/dist/test/unit/engine/resolve.test.d.ts +0 -1
- package/dist/test/unit/engine/resolve.test.js +0 -157
- package/dist/test/unit/engine/resolve.test.js.map +0 -1
- package/dist/test/unit/engine/tokens.test.d.ts +0 -1
- package/dist/test/unit/engine/tokens.test.js +0 -26
- package/dist/test/unit/engine/tokens.test.js.map +0 -1
- package/dist/test/unit/events.test.d.ts +0 -1
- package/dist/test/unit/events.test.js +0 -13
- package/dist/test/unit/events.test.js.map +0 -1
- package/dist/test/unit/metrics.test.d.ts +0 -1
- package/dist/test/unit/metrics.test.js +0 -108
- package/dist/test/unit/metrics.test.js.map +0 -1
- package/dist/test/unit/notify.test.d.ts +0 -1
- package/dist/test/unit/notify.test.js +0 -49
- package/dist/test/unit/notify.test.js.map +0 -1
- package/dist/test/unit/period.test.d.ts +0 -1
- package/dist/test/unit/period.test.js +0 -61
- package/dist/test/unit/period.test.js.map +0 -1
- package/dist/test/unit/permissions.test.d.ts +0 -1
- package/dist/test/unit/permissions.test.js +0 -27
- package/dist/test/unit/permissions.test.js.map +0 -1
- package/dist/test/unit/provider.test.d.ts +0 -1
- package/dist/test/unit/provider.test.js +0 -47
- package/dist/test/unit/provider.test.js.map +0 -1
- package/dist/test/unit/realtime.test.d.ts +0 -1
- package/dist/test/unit/realtime.test.js +0 -13
- package/dist/test/unit/realtime.test.js.map +0 -1
- package/dist/test/unit/render.test.d.ts +0 -1
- package/dist/test/unit/render.test.js +0 -23
- package/dist/test/unit/render.test.js.map +0 -1
- package/dist/test/unit/retention.test.d.ts +0 -1
- package/dist/test/unit/retention.test.js +0 -66
- package/dist/test/unit/retention.test.js.map +0 -1
- package/dist/test/unit/send-batch.test.d.ts +0 -1
- package/dist/test/unit/send-batch.test.js +0 -46
- package/dist/test/unit/send-batch.test.js.map +0 -1
- package/dist/test/unit/send.test.d.ts +0 -1
- package/dist/test/unit/send.test.js +0 -120
- package/dist/test/unit/send.test.js.map +0 -1
- package/dist/test/unit/smoke.test.d.ts +0 -1
- package/dist/test/unit/smoke.test.js +0 -10
- package/dist/test/unit/smoke.test.js.map +0 -1
- package/dist/test/unit/status.test.d.ts +0 -1
- package/dist/test/unit/status.test.js +0 -16
- package/dist/test/unit/status.test.js.map +0 -1
- package/dist/test/unit/templates.test.d.ts +0 -1
- package/dist/test/unit/templates.test.js +0 -48
- package/dist/test/unit/templates.test.js.map +0 -1
- package/dist/test/unit/tenant-export.test.d.ts +0 -1
- package/dist/test/unit/tenant-export.test.js +0 -59
- package/dist/test/unit/tenant-export.test.js.map +0 -1
- package/dist/test/unit/webhook-secret.test.d.ts +0 -1
- package/dist/test/unit/webhook-secret.test.js +0 -43
- package/dist/test/unit/webhook-secret.test.js.map +0 -1
- package/frontend-vue/app/components/AttentionCard.vue +0 -78
- package/frontend-vue/app/components/HtmlPreviewModal.vue +0 -20
- package/frontend-vue/app/components/ProviderChip.vue +0 -39
- package/frontend-vue/app/components/editor/EditorBlockSettings.vue +0 -186
- package/frontend-vue/app/components/editor/EditorDataPanel.vue +0 -130
- package/frontend-vue/app/components/editor/EditorDraftBar.vue +0 -35
- package/frontend-vue/app/components/editor/EditorRail.vue +0 -58
- package/frontend-vue/app/components/editor/EditorSubjectSettings.vue +0 -37
- package/frontend-vue/app/components/editor/EditorTemplateSettings.vue +0 -87
- package/frontend-vue/app/components/editor/EditorTestSendModal.vue +0 -66
- package/frontend-vue/app/components/editor/EditorVariables.vue +0 -163
- package/frontend-vue/app/composables/useMailingPeriodData.ts +0 -39
- package/src/antelope-modules.ts +0 -48
- package/src/test/antelope.test.ts +0 -190
- package/src/test/helpers/http.ts +0 -23
- package/src/test/helpers/owner.ts +0 -37
- package/src/test/integration/events.test.ts +0 -159
- package/src/test/integration/retention.test.ts +0 -363
- package/src/test/integration/sends.test.ts +0 -233
- package/src/test/integration/settings.test.ts +0 -128
- package/src/test/integration/setup.test.ts +0 -35
- package/src/test/integration/templates.test.ts +0 -272
- package/src/test/integration/tenant-export.test.ts +0 -125
- package/src/test/unit/attention.test.ts +0 -129
- package/src/test/unit/automation.test.ts +0 -130
- package/src/test/unit/categories.test.ts +0 -51
- package/src/test/unit/engine/conditions.test.ts +0 -35
- package/src/test/unit/engine/coverage.test.ts +0 -118
- package/src/test/unit/engine/fallback-html.test.ts +0 -86
- package/src/test/unit/engine/paths.test.ts +0 -39
- package/src/test/unit/engine/resolve.test.ts +0 -176
- package/src/test/unit/engine/tokens.test.ts +0 -26
- package/src/test/unit/events.test.ts +0 -19
- package/src/test/unit/metrics.test.ts +0 -170
- package/src/test/unit/notify.test.ts +0 -71
- package/src/test/unit/period.test.ts +0 -91
- package/src/test/unit/permissions.test.ts +0 -30
- package/src/test/unit/provider.test.ts +0 -57
- package/src/test/unit/realtime.test.ts +0 -11
- package/src/test/unit/render.test.ts +0 -23
- package/src/test/unit/retention.test.ts +0 -91
- package/src/test/unit/send-batch.test.ts +0 -72
- package/src/test/unit/send.test.ts +0 -161
- package/src/test/unit/smoke.test.ts +0 -8
- package/src/test/unit/status.test.ts +0 -14
- package/src/test/unit/templates.test.ts +0 -52
- package/src/test/unit/tenant-export.test.ts +0 -88
- package/src/test/unit/webhook-secret.test.ts +0 -51
|
@@ -1,23 +1,49 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
-
import EmailButton from '#dms-layout/app/emails/components/EmailButton.vue'
|
|
4
|
-
import EmailOTP from '#dms-layout/app/emails/components/EmailOTP.vue'
|
|
5
3
|
import { emailStyles } from '#dms-layout/app/emails/components/index'
|
|
4
|
+
import MailingTextLines from './MailingTextLines.vue'
|
|
6
5
|
import type {
|
|
7
6
|
ResolvedBlock,
|
|
7
|
+
ResolvedButton,
|
|
8
|
+
ResolvedFooter,
|
|
8
9
|
ResolvedHeading,
|
|
9
10
|
ResolvedParagraph,
|
|
10
11
|
} from '../../types/mailing'
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
interface FooterLink {
|
|
14
|
+
label: string
|
|
15
|
+
href: string
|
|
16
|
+
}
|
|
13
17
|
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const FOOTER_TYPE = 'footer'
|
|
19
|
+
const FOOTER_LINK_SEPARATOR = ' · '
|
|
20
|
+
|
|
21
|
+
/** Long words (a URL, a reference) wrap instead of widening the e-mail. */
|
|
22
|
+
const wrap = { overflowWrap: 'anywhere', wordBreak: 'break-word' }
|
|
23
|
+
const blockSpacing = { margin: '0 0 16px' }
|
|
24
|
+
const textStyle = { ...emailStyles.text, ...wrap }
|
|
25
|
+
const heroStyle = {
|
|
26
|
+
display: 'block',
|
|
27
|
+
width: '100%',
|
|
28
|
+
borderRadius: '8px',
|
|
29
|
+
margin: '0 0 20px',
|
|
30
|
+
}
|
|
31
|
+
const cellStyle = { ...textStyle, margin: '0' }
|
|
32
|
+
const valueCellStyle = { ...cellStyle, textAlign: 'right' as const }
|
|
33
|
+
const totalStyle = { ...cellStyle, fontWeight: '600' }
|
|
34
|
+
const totalValueStyle = { ...valueCellStyle, fontWeight: '600' }
|
|
35
|
+
const codeStyle = { ...emailStyles.otp.code, ...wrap }
|
|
36
|
+
const dividerStyle = { border: '0', ...emailStyles.divider }
|
|
37
|
+
/** Darker than the DMS footer grey: small print stays readable (4.8:1). */
|
|
38
|
+
const FOOTER_TEXT_COLOR = '#71717a'
|
|
39
|
+
const footerStyle = {
|
|
40
|
+
...emailStyles.footer,
|
|
41
|
+
color: FOOTER_TEXT_COLOR,
|
|
42
|
+
...wrap,
|
|
43
|
+
}
|
|
44
|
+
const footerLinkStyle = {
|
|
45
|
+
color: FOOTER_TEXT_COLOR,
|
|
46
|
+
textDecoration: 'underline',
|
|
21
47
|
}
|
|
22
48
|
|
|
23
49
|
interface Props {
|
|
@@ -27,28 +53,49 @@ interface Props {
|
|
|
27
53
|
|
|
28
54
|
const props = defineProps<Props>()
|
|
29
55
|
|
|
56
|
+
/** A footer with neither text nor link would draw a lone divider. */
|
|
57
|
+
const isEmptyFooter = (block: ResolvedBlock): boolean =>
|
|
58
|
+
block.type === FOOTER_TYPE && !block.text.trim() && !footerLinks(block).length
|
|
59
|
+
|
|
30
60
|
const visibleBlocks = computed(() =>
|
|
31
|
-
props.blocks
|
|
32
|
-
|
|
33
|
-
|
|
61
|
+
props.blocks
|
|
62
|
+
.filter((block) =>
|
|
63
|
+
props.footerOnly
|
|
64
|
+
? block.type === FOOTER_TYPE
|
|
65
|
+
: block.type !== FOOTER_TYPE,
|
|
66
|
+
)
|
|
67
|
+
.filter((block) => !isEmptyFooter(block)),
|
|
34
68
|
)
|
|
35
69
|
|
|
36
70
|
const headingStyle = (block: ResolvedHeading) => ({
|
|
37
71
|
...emailStyles.heading,
|
|
72
|
+
...wrap,
|
|
38
73
|
textAlign: block.align,
|
|
39
74
|
fontSize: `${block.size}px`,
|
|
40
75
|
})
|
|
41
76
|
|
|
42
77
|
const paragraphStyle = (block: ResolvedParagraph) => ({
|
|
43
|
-
...
|
|
78
|
+
...textStyle,
|
|
44
79
|
textAlign: block.align,
|
|
45
80
|
})
|
|
81
|
+
|
|
82
|
+
const buttonRowStyle = (block: ResolvedButton) => ({
|
|
83
|
+
...emailStyles.buttonContainer,
|
|
84
|
+
textAlign: block.align,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
function footerLinks(block: ResolvedFooter): FooterLink[] {
|
|
88
|
+
return [
|
|
89
|
+
{ label: block.unsubscribeLabel, href: block.unsubscribeUrl },
|
|
90
|
+
{ label: block.preferencesLabel, href: block.preferencesUrl },
|
|
91
|
+
].filter((link) => link.href && link.label.trim())
|
|
92
|
+
}
|
|
46
93
|
</script>
|
|
47
94
|
|
|
48
95
|
<template>
|
|
49
96
|
<template v-for="block in visibleBlocks" :key="block.id">
|
|
50
97
|
<EImg
|
|
51
|
-
v-if="block.type === 'hero'"
|
|
98
|
+
v-if="block.type === 'hero' && block.imageUrl"
|
|
52
99
|
:src="block.imageUrl"
|
|
53
100
|
:alt="block.alt"
|
|
54
101
|
:style="heroStyle"
|
|
@@ -59,59 +106,70 @@ const paragraphStyle = (block: ResolvedParagraph) => ({
|
|
|
59
106
|
as="h1"
|
|
60
107
|
:style="headingStyle(block)"
|
|
61
108
|
>
|
|
62
|
-
|
|
109
|
+
<MailingTextLines :text="block.text" />
|
|
63
110
|
</EHeading>
|
|
64
111
|
|
|
65
112
|
<EText
|
|
66
113
|
v-else-if="block.type === 'paragraph'"
|
|
67
114
|
:style="paragraphStyle(block)"
|
|
68
115
|
>
|
|
69
|
-
|
|
116
|
+
<MailingTextLines :text="block.text" />
|
|
70
117
|
</EText>
|
|
71
118
|
|
|
72
|
-
<
|
|
119
|
+
<ESection v-else-if="block.type === 'code'" :style="emailStyles.otp.box">
|
|
120
|
+
<EText :style="codeStyle">{{ block.text }}</EText>
|
|
121
|
+
</ESection>
|
|
73
122
|
|
|
74
|
-
<ESection v-else-if="block.type === 'list'">
|
|
123
|
+
<ESection v-else-if="block.type === 'list'" :style="blockSpacing">
|
|
75
124
|
<ERow v-for="(row, index) in block.rows" :key="index">
|
|
76
125
|
<EColumn>
|
|
77
|
-
<EText :style="
|
|
126
|
+
<EText :style="cellStyle">{{ row.label }}</EText>
|
|
78
127
|
</EColumn>
|
|
79
128
|
<EColumn align="right">
|
|
80
|
-
<EText :style="
|
|
129
|
+
<EText :style="valueCellStyle">{{ row.value }}</EText>
|
|
81
130
|
</EColumn>
|
|
82
131
|
</ERow>
|
|
83
132
|
</ESection>
|
|
84
133
|
|
|
85
|
-
<ESection v-else-if="block.type === 'total'">
|
|
134
|
+
<ESection v-else-if="block.type === 'total'" :style="blockSpacing">
|
|
86
135
|
<ERow>
|
|
87
136
|
<EColumn>
|
|
88
137
|
<EText :style="totalStyle">{{ block.label }}</EText>
|
|
89
138
|
</EColumn>
|
|
90
139
|
<EColumn align="right">
|
|
91
|
-
<EText :style="
|
|
140
|
+
<EText :style="totalValueStyle">{{ block.value }}</EText>
|
|
92
141
|
</EColumn>
|
|
93
142
|
</ERow>
|
|
94
143
|
</ESection>
|
|
95
144
|
|
|
96
145
|
<ESection
|
|
97
146
|
v-else-if="block.type === 'button'"
|
|
98
|
-
:style="
|
|
147
|
+
:style="buttonRowStyle(block)"
|
|
99
148
|
>
|
|
100
|
-
<
|
|
149
|
+
<EButton :href="block.href" :style="emailStyles.button">
|
|
150
|
+
{{ block.text }}
|
|
151
|
+
</EButton>
|
|
101
152
|
</ESection>
|
|
102
153
|
|
|
103
|
-
<EHr v-else-if="block.type === 'divider'" :style="
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
154
|
+
<EHr v-else-if="block.type === 'divider'" :style="dividerStyle" />
|
|
155
|
+
|
|
156
|
+
<template v-else-if="block.type === 'footer'">
|
|
157
|
+
<EHr :style="dividerStyle" />
|
|
158
|
+
<EText :style="footerStyle">
|
|
159
|
+
<MailingTextLines :text="block.text" />
|
|
160
|
+
<template v-if="footerLinks(block).length">
|
|
161
|
+
<br />
|
|
162
|
+
<template
|
|
163
|
+
v-for="(link, index) in footerLinks(block)"
|
|
164
|
+
:key="link.href"
|
|
165
|
+
>
|
|
166
|
+
<template v-if="index > 0">{{ FOOTER_LINK_SEPARATOR }}</template>
|
|
167
|
+
<ELink :href="link.href" :style="footerLinkStyle">
|
|
168
|
+
{{ link.label }}
|
|
169
|
+
</ELink>
|
|
170
|
+
</template>
|
|
171
|
+
</template>
|
|
172
|
+
</EText>
|
|
173
|
+
</template>
|
|
116
174
|
</template>
|
|
117
175
|
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
text: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const LINE_BREAK = /\r?\n/
|
|
9
|
+
|
|
10
|
+
const props = defineProps<Props>()
|
|
11
|
+
|
|
12
|
+
const lines = computed(() => props.text.split(LINE_BREAK))
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<template v-for="(line, index) in lines" :key="index">
|
|
17
|
+
<br v-if="index > 0" />
|
|
18
|
+
{{ line }}
|
|
19
|
+
</template>
|
|
20
|
+
</template>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { h, type VNode } from 'vue'
|
|
2
|
+
import CategoryLabel from '../components/CategoryLabel.vue'
|
|
3
|
+
import { localeChipClass, localeChips } from '../utils/locales'
|
|
4
|
+
|
|
5
|
+
export const LOCALE_CHIPS_DISPLAY_ID = 'mailing:locale-chips'
|
|
6
|
+
export const CATEGORY_DISPLAY_ID = 'mailing:category'
|
|
7
|
+
|
|
8
|
+
const EMPTY_CELL = '—'
|
|
9
|
+
const CHIP_ROW_CLASS = 'inline-flex items-center gap-1'
|
|
10
|
+
|
|
11
|
+
interface WorkspaceLocale {
|
|
12
|
+
code: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const emptyCell = () => h('span', { class: 'text-dimmed' }, EMPTY_CELL)
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A template's locales as mono chips, the workspace locales it lacks drawn
|
|
19
|
+
* dashed in the warning tone, like the gallery card.
|
|
20
|
+
*/
|
|
21
|
+
export function renderLocaleChips(
|
|
22
|
+
value: unknown,
|
|
23
|
+
workspaceCodes: string[],
|
|
24
|
+
): VNode {
|
|
25
|
+
const chips = localeChips(
|
|
26
|
+
typeof value === 'string' ? value : '',
|
|
27
|
+
workspaceCodes,
|
|
28
|
+
)
|
|
29
|
+
if (!chips.length) return emptyCell()
|
|
30
|
+
return h(
|
|
31
|
+
'span',
|
|
32
|
+
{ class: CHIP_ROW_CLASS },
|
|
33
|
+
chips.map((chip) =>
|
|
34
|
+
h('span', { class: localeChipClass(chip.present) }, chip.code),
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** A template's category as its settings label and icon. */
|
|
40
|
+
export function renderCategory(value: unknown): VNode {
|
|
41
|
+
return h(CategoryLabel, { value: typeof value === 'string' ? value : null })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function workspaceCodes(): string[] {
|
|
45
|
+
const { uniqueLocales } = useUniqueLocales()
|
|
46
|
+
return uniqueLocales.value.map((entry: WorkspaceLocale) => entry.code)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Frontend renderers of the backend column displays `mailing:locale-chips`
|
|
51
|
+
* and `mailing:category` (`src/data/displays.ts`).
|
|
52
|
+
*/
|
|
53
|
+
export default defineDmsPlugin(() => {
|
|
54
|
+
const { registerDataType } = useDataTypes()
|
|
55
|
+
registerDataType({
|
|
56
|
+
id: LOCALE_CHIPS_DISPLAY_ID,
|
|
57
|
+
formatter: {
|
|
58
|
+
default: (value: unknown) => renderLocaleChips(value, workspaceCodes()),
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
registerDataType({
|
|
62
|
+
id: CATEGORY_DISPLAY_ID,
|
|
63
|
+
formatter: { default: renderCategory },
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -253,6 +253,7 @@ export type SendStatus =
|
|
|
253
253
|
| 'spam'
|
|
254
254
|
| 'failed'
|
|
255
255
|
| 'unsubscribed'
|
|
256
|
+
| 'suppressed'
|
|
256
257
|
|
|
257
258
|
export const SEND_STATUSES: SendStatus[] = [
|
|
258
259
|
'queued',
|
|
@@ -264,9 +265,11 @@ export const SEND_STATUSES: SendStatus[] = [
|
|
|
264
265
|
'spam',
|
|
265
266
|
'failed',
|
|
266
267
|
'unsubscribed',
|
|
268
|
+
'suppressed',
|
|
267
269
|
]
|
|
268
270
|
|
|
269
|
-
|
|
271
|
+
/** What a provider reports: a suppressed send never reached one. */
|
|
272
|
+
export type SendEventType = Exclude<SendStatus, 'suppressed'>
|
|
270
273
|
|
|
271
274
|
export interface TemplateCategory {
|
|
272
275
|
id: string
|
|
@@ -278,26 +281,140 @@ export interface TemplateRow {
|
|
|
278
281
|
_id: string
|
|
279
282
|
slug: string
|
|
280
283
|
name: string
|
|
281
|
-
/** Absent or empty when the template is uncategorised. */
|
|
282
|
-
category?: string
|
|
284
|
+
/** Absent, `null` or empty when the template is uncategorised. */
|
|
285
|
+
category?: string | null
|
|
283
286
|
status: TemplateStatus
|
|
284
287
|
/** Comma-separated locale codes of the content; blank means unknown. */
|
|
285
288
|
locales?: string
|
|
286
289
|
updatedAt: string
|
|
287
290
|
updatedBy: string
|
|
291
|
+
/** Version customers receive; 0 or absent when never published. */
|
|
292
|
+
publishedVersion?: number
|
|
293
|
+
publishedAt?: string | null
|
|
294
|
+
/** When the template last left `live` by an unpublish. */
|
|
295
|
+
unpublishedAt?: string | null
|
|
296
|
+
/** Whether a draft holds changes customers do not receive yet. */
|
|
297
|
+
isDraftPending?: boolean
|
|
298
|
+
/** Why the template needs a look, comma-separated; blank when nothing does. */
|
|
299
|
+
attention: string
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export type TemplateChangeKind =
|
|
303
|
+
| 'locale_added'
|
|
304
|
+
| 'locale_removed'
|
|
305
|
+
| 'subject'
|
|
306
|
+
| 'preheader'
|
|
307
|
+
| 'block_added'
|
|
308
|
+
| 'block_removed'
|
|
309
|
+
| 'block_changed'
|
|
310
|
+
| 'blocks_reordered'
|
|
311
|
+
| 'variable_added'
|
|
312
|
+
| 'variable_removed'
|
|
313
|
+
| 'variable_changed'
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* One difference between what customers receive and the draft: per locale
|
|
317
|
+
* for the content, per path for the variable declarations.
|
|
318
|
+
*/
|
|
319
|
+
export interface TemplateChange {
|
|
320
|
+
/** Blank for a change of the variable declarations. */
|
|
321
|
+
locale: string
|
|
322
|
+
kind: TemplateChangeKind
|
|
323
|
+
blockId?: string
|
|
324
|
+
blockType?: BlockType
|
|
325
|
+
/** The declared path a variable change is about. */
|
|
326
|
+
variable?: string
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export interface TemplateSender {
|
|
330
|
+
name: string
|
|
331
|
+
email: string
|
|
332
|
+
replyTo: string
|
|
288
333
|
}
|
|
289
334
|
|
|
290
335
|
export interface TemplateContentResponse {
|
|
291
|
-
template: TemplateRow
|
|
336
|
+
template: TemplateRow & {
|
|
337
|
+
json_variables?: string
|
|
338
|
+
draftUpdatedAt?: string
|
|
339
|
+
draftUpdatedBy?: string
|
|
340
|
+
publishedBy?: string
|
|
341
|
+
}
|
|
342
|
+
/** The content the editor works on: the draft, else the published one. */
|
|
292
343
|
content: TemplateContent
|
|
344
|
+
/** What customers receive; `null` when the template was never published. */
|
|
345
|
+
publishedContent: TemplateContent | null
|
|
346
|
+
hasDraft: boolean
|
|
347
|
+
/** Version customers receive; 0 when never published. */
|
|
348
|
+
version: number
|
|
349
|
+
/** The draft revision a save or a publish carries back. */
|
|
350
|
+
revision: number
|
|
351
|
+
changes: TemplateChange[]
|
|
352
|
+
/** The declarations the editor works on: the draft's, else the published. */
|
|
293
353
|
variables: VariableDefinition[]
|
|
294
|
-
/** Paths the content
|
|
354
|
+
/** Paths the working content references, across every locale. */
|
|
295
355
|
detectedVariables: string[]
|
|
356
|
+
/**
|
|
357
|
+
* The contract callers send against: the published declarations and the
|
|
358
|
+
* paths the published content references; `null` when never published.
|
|
359
|
+
*/
|
|
360
|
+
publishedVariables?: VariableDefinition[] | null
|
|
361
|
+
publishedDetectedVariables?: string[] | null
|
|
296
362
|
testData: Record<string, unknown>
|
|
297
363
|
fallbackLocale: string
|
|
364
|
+
/** Whether a send missing a variable fails rather than goes out blank. */
|
|
365
|
+
blockOnMissingVariables: boolean
|
|
298
366
|
categories: TemplateCategory[]
|
|
367
|
+
sender: TemplateSender
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export interface TemplateVersionSummary {
|
|
371
|
+
version: number
|
|
372
|
+
publishedAt: string
|
|
373
|
+
publishedBy: string
|
|
374
|
+
locales: string
|
|
375
|
+
changes: TemplateChange[]
|
|
376
|
+
/** The declarations the version shipped with. */
|
|
377
|
+
variables: VariableDefinition[]
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/** Last 30 days of real sends of one template. */
|
|
381
|
+
export interface TemplateStats {
|
|
382
|
+
id: string
|
|
383
|
+
slug: string
|
|
384
|
+
sends: number
|
|
385
|
+
openRate: number
|
|
386
|
+
problems: number
|
|
387
|
+
lastSentAt: string | null
|
|
299
388
|
}
|
|
300
389
|
|
|
390
|
+
export interface SourceCount {
|
|
391
|
+
source: string
|
|
392
|
+
count: number
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Recipients who asked for a locale the template did not carry. */
|
|
396
|
+
export interface FallbackCount {
|
|
397
|
+
requested: string
|
|
398
|
+
used: string
|
|
399
|
+
count: number
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export interface TemplatePerformance extends TemplateStats {
|
|
403
|
+
sources: SourceCount[]
|
|
404
|
+
fallbacks: FallbackCount[]
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface StarterSummary {
|
|
408
|
+
id: string
|
|
409
|
+
name: string
|
|
410
|
+
slug: string
|
|
411
|
+
category: string
|
|
412
|
+
locales: string[]
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Which content a preview renders when it carries none. */
|
|
416
|
+
export type PreviewVersion = 'draft' | 'published' | number
|
|
417
|
+
|
|
301
418
|
export interface PreviewResponse {
|
|
302
419
|
html: string
|
|
303
420
|
subject: string
|
|
@@ -306,17 +423,31 @@ export interface PreviewResponse {
|
|
|
306
423
|
hiddenBlockIds: string[]
|
|
307
424
|
}
|
|
308
425
|
|
|
426
|
+
export type SendStage =
|
|
427
|
+
| 'problem'
|
|
428
|
+
| 'resolved'
|
|
429
|
+
| 'suppressed'
|
|
430
|
+
| 'in_progress'
|
|
431
|
+
| 'delivered'
|
|
432
|
+
| 'engaged'
|
|
433
|
+
| 'unsubscribed'
|
|
434
|
+
|
|
309
435
|
export interface SendRow {
|
|
310
436
|
_id: string
|
|
311
437
|
templateId: string
|
|
312
438
|
templateSlug: string
|
|
313
439
|
locale: string
|
|
440
|
+
/** Locale the caller asked for; differs from `locale` on a fallback. */
|
|
441
|
+
requestedLocale?: string
|
|
442
|
+
/** Template version the send used; 0 for a test send of a draft. */
|
|
443
|
+
templateVersion?: number
|
|
444
|
+
stage?: SendStage
|
|
314
445
|
recipientEmail: string
|
|
315
446
|
recipientName?: string
|
|
316
447
|
status: SendStatus
|
|
317
448
|
provider?: string
|
|
318
449
|
providerMessageId?: string
|
|
319
|
-
latencyMs: number
|
|
450
|
+
latencyMs: number | null
|
|
320
451
|
error?: string
|
|
321
452
|
source?: string
|
|
322
453
|
json_variables: string
|
|
@@ -324,38 +455,72 @@ export interface SendRow {
|
|
|
324
455
|
clicks: number
|
|
325
456
|
createdAt: string
|
|
326
457
|
isTest: boolean
|
|
458
|
+
/** The send this one repeats. */
|
|
459
|
+
replayOf?: string
|
|
460
|
+
/** The send that repeated this one, once someone sent it again. */
|
|
461
|
+
replayedBy?: string
|
|
462
|
+
/** When someone sent it again. */
|
|
463
|
+
resolvedAt?: string
|
|
464
|
+
/** Who sent it again: a user id. */
|
|
465
|
+
resolvedBy?: string
|
|
327
466
|
}
|
|
328
467
|
|
|
329
468
|
export interface SendEventRow {
|
|
330
469
|
_id: string
|
|
331
470
|
sendId: string
|
|
332
|
-
type:
|
|
471
|
+
type: SendEventType
|
|
333
472
|
at: string
|
|
334
473
|
json_details: string
|
|
335
474
|
}
|
|
336
475
|
|
|
476
|
+
export type SuppressionReason =
|
|
477
|
+
'hard_bounce' | 'complaint' | 'unsubscribe' | 'manual'
|
|
478
|
+
|
|
479
|
+
/** An address's entry on the suppression list, as the API answers it. */
|
|
480
|
+
export interface SuppressionSummary {
|
|
481
|
+
id: string
|
|
482
|
+
email: string
|
|
483
|
+
reason: SuppressionReason
|
|
484
|
+
createdAt: string
|
|
485
|
+
/** The send whose event put the address on the list. */
|
|
486
|
+
sendId?: string
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
export interface SendTemplateSummary {
|
|
490
|
+
id: string
|
|
491
|
+
name: string
|
|
492
|
+
status: TemplateStatus
|
|
493
|
+
publishedVersion: number
|
|
494
|
+
}
|
|
495
|
+
|
|
337
496
|
export interface SendDetailResponse {
|
|
338
497
|
send: SendRow
|
|
339
498
|
events: SendEventRow[]
|
|
499
|
+
/** `null` when the template was deleted since. */
|
|
500
|
+
template: SendTemplateSummary | null
|
|
501
|
+
/** The recipient's entry on the suppression list, if any. */
|
|
502
|
+
suppression?: SuppressionSummary | null
|
|
340
503
|
}
|
|
341
504
|
|
|
342
|
-
export
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
params?: Record<string, string | number>
|
|
505
|
+
export interface SendHtmlResponse {
|
|
506
|
+
html: string
|
|
507
|
+
subject: string
|
|
508
|
+
locale: string
|
|
509
|
+
version: number
|
|
510
|
+
/** A draft test is rendered from today's draft, which may differ from what was sent. */
|
|
511
|
+
approximate?: boolean
|
|
512
|
+
from: string
|
|
513
|
+
fromName: string
|
|
352
514
|
}
|
|
353
515
|
|
|
354
516
|
export interface FunnelStep {
|
|
355
517
|
id: string
|
|
356
518
|
label: string
|
|
357
519
|
count: number
|
|
358
|
-
|
|
520
|
+
/** Share of the previous step; `null` when there is nothing to divide by. */
|
|
521
|
+
rate: number | null
|
|
522
|
+
/** `false` when nothing reports the events this step counts. */
|
|
523
|
+
isMeasured?: boolean
|
|
359
524
|
}
|
|
360
525
|
|
|
361
526
|
export interface ProviderInfo {
|
|
@@ -363,3 +528,13 @@ export interface ProviderInfo {
|
|
|
363
528
|
connected: boolean
|
|
364
529
|
features: Record<string, boolean> | null
|
|
365
530
|
}
|
|
531
|
+
|
|
532
|
+
export type MissingVariablesPolicy = 'refuse' | 'send'
|
|
533
|
+
|
|
534
|
+
export interface RetentionPreview {
|
|
535
|
+
days: number
|
|
536
|
+
count: number
|
|
537
|
+
nextRunAt: string
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export type FunnelKind = 'all' | 'marketing' | 'transactional'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** What a failed `$authFetch` call carries, as far as the module reads it. */
|
|
2
|
+
export interface FetchFailure {
|
|
3
|
+
statusCode?: number
|
|
4
|
+
status?: number
|
|
5
|
+
data?: unknown
|
|
6
|
+
message?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const HTTP_CONFLICT = 409
|
|
10
|
+
|
|
11
|
+
const asFailure = (error: unknown): FetchFailure =>
|
|
12
|
+
error !== null && typeof error === 'object' ? (error as FetchFailure) : {}
|
|
13
|
+
|
|
14
|
+
/** The HTTP status of a failed call; 0 for a network failure. */
|
|
15
|
+
export function apiErrorStatus(error: unknown): number {
|
|
16
|
+
const failure = asFailure(error)
|
|
17
|
+
return failure.statusCode ?? failure.status ?? 0
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The message a failed call answers: the backend's i18n key (`$dms_mailing…`)
|
|
22
|
+
* when it sent one, else the error's own text, for `processApiMessage`.
|
|
23
|
+
*/
|
|
24
|
+
export function apiErrorMessage(error: unknown): string {
|
|
25
|
+
const failure = asFailure(error)
|
|
26
|
+
const data = failure.data
|
|
27
|
+
if (data && typeof data === 'object') {
|
|
28
|
+
const message = (data as Record<string, unknown>).message
|
|
29
|
+
if (typeof message === 'string') return message
|
|
30
|
+
}
|
|
31
|
+
if (typeof data === 'string' && data) return data
|
|
32
|
+
return failure.message ?? String(error)
|
|
33
|
+
}
|