diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md
index 06531c46ba7..59a0c3ef0cc 100644
--- a/CHANGELOG.unreleased.md
+++ b/CHANGELOG.unreleased.md
@@ -8,6 +8,7 @@
> Users must be able to say: “Nice enhancement, I'm eager to test it”
- [VM] Disks whose name contains the tag `[NOSNAP]` will be ignored when doing a manual snapshot similarly to disks ignored during backups with `[NOBAK]` (possibility to use both tags on the same disk) [Forum#79179](https://xcp-ng.org/forum/post/79179)
+- [Plugin/backup-reports] Backup reports sent by email have a new, less rudimentary look (PR [#7747](https://github.com/vatesfr/xen-orchestra/pull/7747))
### Bug fixes
@@ -33,6 +34,7 @@
- @xen-orchestra/xapi major
- xo-server minor
+- xo-server-backup-reports minor
- xo-server-sdn-controller patch
diff --git a/packages/xo-server-backup-reports/package.json b/packages/xo-server-backup-reports/package.json
index cffa104130b..f4766dd1123 100644
--- a/packages/xo-server-backup-reports/package.json
+++ b/packages/xo-server-backup-reports/package.json
@@ -37,6 +37,7 @@
"handlebars": "^4.7.8",
"human-format": "^1.0.0",
"lodash": "^4.13.1",
+ "mjml": "^4.15.3",
"moment-timezone": "^0.5.13"
},
"devDependencies": {
diff --git a/packages/xo-server-backup-reports/src/helpers.js b/packages/xo-server-backup-reports/src/helpers.js
index d91d2b512a2..95e9420be5f 100644
--- a/packages/xo-server-backup-reports/src/helpers.js
+++ b/packages/xo-server-backup-reports/src/helpers.js
@@ -1,4 +1,3 @@
-import Handlebars from 'handlebars'
import humanFormat from 'human-format'
import moment from 'moment-timezone'
@@ -15,15 +14,15 @@ const STATUS_ICON = {
}
const TITLE_BY_STATUS = {
- failure: n => `## ${n} Failure${n === 1 ? '' : 's'}`,
- interrupted: n => `## ${n} Interrupted`,
- skipped: n => `## ${n} Skipped`,
- success: n => `## ${n} Success${n === 1 ? '' : 'es'}`,
+ failure: n => `${n} Failure${n === 1 ? '' : 's'}`,
+ interrupted: n => `${n} Interrupted`,
+ skipped: n => `${n} Skipped`,
+ success: n => `${n} Success${n === 1 ? '' : 'es'}`,
}
// ===================================================================
-Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
+export function ifCond(v1, operator, v2, options) {
switch (operator) {
case '===':
return v1 === v2 ? options.fn(this) : options.inverse(this)
@@ -44,36 +43,34 @@ Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
default:
return options.inverse(this)
}
-})
+}
-Handlebars.registerHelper('formatDuration', milliseconds => moment.duration(milliseconds).humanize())
+export const formatDuration = milliseconds => moment.duration(milliseconds).humanize()
-const formatSize = bytes =>
+export const formatSize = bytes =>
humanFormat(bytes, {
scale: 'binary',
unit: 'B',
})
-Handlebars.registerHelper('formatSize', formatSize)
-const formatSpeed = (bytes, milliseconds) =>
- milliseconds > 0
- ? humanFormat((bytes * 1e3) / milliseconds, {
+export const formatSpeed = (bytes, start, end) =>
+ end - start > 0
+ ? humanFormat((bytes * 1e3) / (end - start), {
scale: 'binary',
unit: 'B/s',
})
: 'N/A'
-Handlebars.registerHelper('formatSpeed', (bytes, start, end) => formatSpeed(bytes, end - start))
-Handlebars.registerHelper('subtract', (a, b) => a - b)
+export const subtract = (a, b) => a - b
-Handlebars.registerHelper('executeFunction', (fct, arg) => fct(arg))
+export const executeFunction = (fct, arg) => fct(arg)
// this could be a partial but it would be less clear
-Handlebars.registerHelper('getIcon', status => STATUS_ICON[status])
+export const getIcon = status => STATUS_ICON[status]
// this could be a partial but it would be less clear
-Handlebars.registerHelper('titleByStatus', function (status) {
- if (this && status in TITLE_BY_STATUS) {
- return TITLE_BY_STATUS[status](this.length)
+export function titleByStatus(status, tasks) {
+ if (tasks && status in TITLE_BY_STATUS) {
+ return TITLE_BY_STATUS[status](tasks.length)
}
-})
+}
diff --git a/packages/xo-server-backup-reports/src/index.js b/packages/xo-server-backup-reports/src/index.js
index 5ce859be6ec..f762a3f69f8 100644
--- a/packages/xo-server-backup-reports/src/index.js
+++ b/packages/xo-server-backup-reports/src/index.js
@@ -1,12 +1,14 @@
import Handlebars from 'handlebars'
import moment from 'moment-timezone'
import { createLogger } from '@xen-orchestra/log'
-import { forEach, groupBy } from 'lodash'
-import { get } from '@xen-orchestra/defined'
import { extname, join, parse } from 'node:path'
+import { get } from '@xen-orchestra/defined'
+import { forEach, groupBy } from 'lodash'
import { readdirSync, readFileSync } from 'node:fs'
+
import pkg from '../package'
-import './helpers'
+
+import * as helpers from './helpers'
const logger = createLogger('xo:xo-server-backup-reports')
@@ -53,26 +55,49 @@ export const testSchema = {
// ===================================================================
-const handlebarsPartialFiles = readdirSync(join(__dirname, '../templates/partials/')).filter(
- filename => extname(filename) === '.hbs'
-)
-for (const fileName of handlebarsPartialFiles) {
- const partial = readFileSync(join(__dirname, `../templates/partials/${fileName}`)).toString()
- Handlebars.registerPartial(parse(fileName).name, partial)
+// Handlebars environments
+const markdownHandlebars = Handlebars.create()
+const mjmlHandlebars = Handlebars.create()
+
+// Handlebars common helpers
+for (const [helperName, helper] of Object.entries(helpers)) {
+ markdownHandlebars.registerHelper(helperName, helper)
+ mjmlHandlebars.registerHelper(helperName, helper)
+}
+
+// Handlebars partials
+const registerPartials = (path, handlebarsEnvironment) => {
+ const handlebarsPartialFiles = readdirSync(join(__dirname, path)).filter(filename => extname(filename) === '.hbs')
+ for (const fileName of handlebarsPartialFiles) {
+ const partial = readFileSync(join(__dirname, `${path}${fileName}`)).toString()
+ handlebarsEnvironment.registerPartial(parse(fileName).name, partial)
+ }
+}
+registerPartials('../templates/markdown/partials/', markdownHandlebars)
+registerPartials('../templates/mjml/partials/', mjmlHandlebars)
+
+// Handlebars templates
+const readCompileHbs = (path, handlebarsEnvironment) =>
+ handlebarsEnvironment.compile(readFileSync(join(__dirname, path)).toString().replace(/\n$/, ''))
+const importTemplateFolder = (folder, handlebarsEnvironment) => ({
+ metadata: readCompileHbs(`${folder}/metadata.hbs`, handlebarsEnvironment),
+ metadataSubject: readCompileHbs(`${folder}/metadataSubject.hbs`, handlebarsEnvironment),
+ vm: readCompileHbs(`${folder}/vm.hbs`, handlebarsEnvironment),
+ vmSubject: readCompileHbs(`${folder}/vmSubject.hbs`, handlebarsEnvironment),
+})
+
+const templates = {
+ markdown: importTemplateFolder('../templates/markdown', markdownHandlebars),
+ mjml: importTemplateFolder('../templates/mjml', mjmlHandlebars),
}
-const compiledMetadataSubject = Handlebars.compile(
- readFileSync(join(__dirname, '../templates/metadataSubject.hbs')).toString().replace(/\n$/, '')
-)
-const compiledMetadataTemplate = Handlebars.compile(
- readFileSync(join(__dirname, '../templates/metadata.hbs')).toString().replace(/\n$/, '')
-)
-const compiledVmSubject = Handlebars.compile(
- readFileSync(join(__dirname, '../templates/vmSubject.hbs')).toString().replace(/\n$/, '')
-)
-const compiledVmTemplate = Handlebars.compile(
- readFileSync(join(__dirname, '../templates/vm.hbs')).toString().replace(/\n$/, '')
-)
+// Templates transforms
+const templatesTransform = {}
+for (const name of ['markdown', 'mjml']) {
+ import(`../templates/${name}/transform.js`).then(module => {
+ templatesTransform[name] = module.transform
+ })
+}
// ===================================================================
@@ -88,7 +113,7 @@ const noop = Function.prototype
const UNHEALTHY_VDI_CHAIN_ERROR = 'unhealthy VDI chain'
const UNHEALTHY_VDI_CHAIN_MESSAGE =
- '[(unhealthy VDI chain) Job canceled to protect the VDI chain](https://xen-orchestra.com/docs/backup_troubleshooting.html#vdi-chain-protection)'
+ '(unhealthy VDI chain) Job canceled to protect the VDI chain. See https://xen-orchestra.com/docs/backup_troubleshooting.html#vdi-chain-protection'
const getAdditionnalData = async (task, props) => {
if (task.data?.type === 'remote') {
@@ -207,8 +232,9 @@ class BackupReportsXoPlugin {
}
return this._sendReport({
- subject: compiledMetadataSubject(context),
- markdown: compiledMetadataTemplate(context),
+ ...(await templatesTransform.markdown(templates.markdown.metadata(context))),
+ ...(await templatesTransform.mjml(templates.mjml.metadata(context))),
+ subject: templates.mjml.metadataSubject(context),
success: log.status === 'success',
})
}
@@ -384,14 +410,15 @@ class BackupReportsXoPlugin {
}
return this._sendReport({
+ ...(await templatesTransform.markdown(templates.markdown.vm(context))),
+ ...(await templatesTransform.mjml(templates.mjml.vm(context))),
mailReceivers,
- markdown: compiledVmTemplate(context),
- subject: compiledVmSubject(context),
+ subject: templates.mjml.vmSubject(context),
success: log.status === 'success',
})
}
- async _sendReport({ mailReceivers, markdown, subject, success }) {
+ async _sendReport({ mailReceivers, markdown, html, subject, success }) {
if (mailReceivers === undefined || mailReceivers.length === 0) {
mailReceivers = this._mailsReceivers
}
@@ -404,7 +431,8 @@ class BackupReportsXoPlugin {
: xo.sendEmail({
to: mailReceivers,
subject,
- markdown,
+ html,
+ text: markdown,
})),
this._xmppReceivers !== undefined &&
(xo.sendEmail === undefined
diff --git a/packages/xo-server-backup-reports/templates/metadata.hbs b/packages/xo-server-backup-reports/templates/markdown/metadata.hbs
similarity index 96%
rename from packages/xo-server-backup-reports/templates/metadata.hbs
rename to packages/xo-server-backup-reports/templates/markdown/metadata.hbs
index ef6fddc2157..5d4deeb379f 100644
--- a/packages/xo-server-backup-reports/templates/metadata.hbs
+++ b/packages/xo-server-backup-reports/templates/markdown/metadata.hbs
@@ -12,7 +12,7 @@
{{#each tasksByStatus}}
---
-{{titleByStatus @key}}
+## {{titleByStatus @key .}}
{{#each this}}
diff --git a/packages/xo-server-backup-reports/templates/metadataSubject.hbs b/packages/xo-server-backup-reports/templates/markdown/metadataSubject.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/metadataSubject.hbs
rename to packages/xo-server-backup-reports/templates/markdown/metadataSubject.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/metadataSubTask.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/metadataSubTask.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/metadataSubTask.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/metadataSubTask.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/reportError.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/reportError.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/reportError.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/reportError.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/reportTemporalData.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/reportTemporalData.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/reportTemporalData.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/reportTemporalData.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/reportWarnings.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/reportWarnings.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/reportWarnings.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/reportWarnings.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/taskBody.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/taskBody.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/taskBody.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/taskBody.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/taskTitle.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/taskTitle.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/taskTitle.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/taskTitle.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmFailure.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmFailure.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmFailure.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmFailure.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmInterrupted.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmInterrupted.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmInterrupted.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmInterrupted.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmSkipped.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmSkipped.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmSkipped.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmSkipped.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmSubTask.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmSubTask.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmSubTask.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmSubTask.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmSubText.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmSubText.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmSubText.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmSubText.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmSuccess.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmSuccess.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmSuccess.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmSuccess.hbs
diff --git a/packages/xo-server-backup-reports/templates/partials/vmText.hbs b/packages/xo-server-backup-reports/templates/markdown/partials/vmText.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/partials/vmText.hbs
rename to packages/xo-server-backup-reports/templates/markdown/partials/vmText.hbs
diff --git a/packages/xo-server-backup-reports/templates/markdown/transform.js b/packages/xo-server-backup-reports/templates/markdown/transform.js
new file mode 100644
index 00000000000..487d6547586
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/markdown/transform.js
@@ -0,0 +1,5 @@
+'use strict'
+
+exports.transform = async function transform(source) {
+ return { markdown: source }
+}
diff --git a/packages/xo-server-backup-reports/templates/vm.hbs b/packages/xo-server-backup-reports/templates/markdown/vm.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/vm.hbs
rename to packages/xo-server-backup-reports/templates/markdown/vm.hbs
diff --git a/packages/xo-server-backup-reports/templates/vmSubject.hbs b/packages/xo-server-backup-reports/templates/markdown/vmSubject.hbs
similarity index 100%
rename from packages/xo-server-backup-reports/templates/vmSubject.hbs
rename to packages/xo-server-backup-reports/templates/markdown/vmSubject.hbs
diff --git a/packages/xo-server-backup-reports/templates/mjml/metadata.hbs b/packages/xo-server-backup-reports/templates/mjml/metadata.hbs
new file mode 100644
index 00000000000..6ee3eaab69d
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/metadata.hbs
@@ -0,0 +1,79 @@
+
+ {{>mjmlHeaders}}
+
+
+
+
+
+ Metadata backup report
+
+
+
+
+
+
+
+
+
+
+ Global status : {{log.status}} {{getIcon log.status}}
+
+ - Job ID: {{log.jobId}}
+ - Job name: {{jobName}}
+ - Run ID: {{log.id}}
+ {{>reportTemporalData end=log.end start=log.start}} {{#if log.tasks.length}}
+ -
+ Successes: {{#if tasksByStatus.success.length ~}}
+ {{tasksByStatus.success.length}} {{~else~}} 0 {{~/if}} / {{log.tasks.length}}
+
+ {{/if}} {{>reportError task=log}} {{>reportWarnings task=log}}
+
+
+
+
+
+ {{#each tasksByStatus}}
+
+
+
+
+ {{titleByStatus @key .}}
+
+
+
+ {{#each this}}
+
+
+
+ {{>taskTitle task=. jobName=../../log.jobName}}
+
+ {{>taskBody task=.}} {{>reportTemporalData formatDate=../../formatDate}} {{>reportError task=.}}
+ {{>reportWarnings task=this}}
+
+
+
+
+ {{#each this.tasks}}
+
+
+
+ {{>taskTitle task=. jobName=''}} {{getIcon status}}
+
+ {{>taskBody task=.}}
+ {{>reportTemporalData formatDate=../../../formatDate}}
+ {{>reportError task=.}}
+ {{>reportWarnings task =.}}
+
+
+
+
+ {{/each}}
+ {{/each}}
+ {{/each}}
+
+ {{>mjmlFooter}}
+
+
+
diff --git a/packages/xo-server-backup-reports/templates/mjml/metadataSubject.hbs b/packages/xo-server-backup-reports/templates/mjml/metadataSubject.hbs
new file mode 100644
index 00000000000..90f103c6b2b
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/metadataSubject.hbs
@@ -0,0 +1 @@
+[Xen Orchestra] {{{log.status}}} − Metadata backup report for {{{log.jobName}}} {{{getIcon log.status}}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/mjmlFooter.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/mjmlFooter.hbs
new file mode 100644
index 00000000000..5892551c658
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/mjmlFooter.hbs
@@ -0,0 +1,14 @@
+
+
+
+ {{pkg.name}} v{{pkg.version}}
+
+
+
+
+
+
+
+
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/mjmlHeaders.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/mjmlHeaders.hbs
new file mode 100644
index 00000000000..077640f0259
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/mjmlHeaders.hbs
@@ -0,0 +1,16 @@
+
+ Backup report
+
+
+
+
+
+
+
+
+ a { color: #fffce4; } a:hover { color: #be1621; } p { color: #fffce4; font-weight: 200; line-height:22px; } h2 {
+ margin-top: 10px; margin-bottom: 0px; } h3 { font-weight: 500; margin-top: 0; margin-bottom: 13px; font-size:
+ 20px; } h3 a { color: #fffce4; text-decoration: none; } h3 a:hover { color: #be1621; border-bottom:
+ 1px solid #be1621; } ul { margin:0px; }
+
+
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/reportError.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/reportError.hbs
new file mode 100644
index 00000000000..b6d69904ee1
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/reportError.hbs
@@ -0,0 +1,7 @@
+{{#ifCond task.status '!==' 'success'}}
+{{#if task.result.message}}
+
{{#ifCond task.status '===' 'skipped'~}} Reason {{~^~}} Error {{~/ifCond}}: {{task.result.message}}
+{{else if task.result.code}}
+{{#ifCond task.status '===' 'skipped'~}} Reason {{~^~}} Error {{~/ifCond}}: {{task.result.code}}
+{{/if}}
+{{/ifCond}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/reportTemporalData.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/reportTemporalData.hbs
new file mode 100644
index 00000000000..21a3b6afd61
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/reportTemporalData.hbs
@@ -0,0 +1,7 @@
+Start time: {{executeFunction formatDate start}}
+{{#if end}}
+End time: {{executeFunction formatDate end}}
+{{#ifCond (subtract end start) '>=' 1}}
+Duration: {{formatDuration (subtract end start)}}
+{{/ifCond}}
+{{/if}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/reportWarnings.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/reportWarnings.hbs
new file mode 100644
index 00000000000..44d25b48c8b
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/reportWarnings.hbs
@@ -0,0 +1,3 @@
+{{#each task.warnings}}
+⚠️ {{message}}
+{{/each}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/taskBody.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/taskBody.hbs
new file mode 100644
index 00000000000..6edf9c4967e
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/taskBody.hbs
@@ -0,0 +1,10 @@
+{{#ifCond task.data.type '===' 'remote'}}
+ID: {{task.data.id}}
+{{/ifCond}}
+{{#ifCond task.data.type '===' 'pool'}}
+{{#if task.data.pool.uuid}}
+UUID: {{task.data.pool.uuid}}
+{{else}}
+ID: {{task.data.id}}
+{{/if}}
+{{/ifCond}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/taskTitle.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/taskTitle.hbs
new file mode 100644
index 00000000000..cb83ec457e0
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/taskTitle.hbs
@@ -0,0 +1,9 @@
+{{#ifCond task.data.type '===' 'xo'}}
+[XO] {{{jobName}}}
+{{~/ifCond}}
+{{#ifCond task.data.type '===' 'remote'}}
+[remote] {{{task.additionnalData.name}}}
+{{~/ifCond}}
+{{#ifCond task.data.type '===' 'pool'}}
+[pool] {{#if task.data.pool.name_label ~}} {{{task.data.pool.name_label}}} {{~else if task.data.poolMaster.name_label ~}} {{{task.data.poolMaster.name_label}}} {{~else~}} Unknown {{~/if}}
+{{~/ifCond}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmFailure.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmFailure.hbs
new file mode 100644
index 00000000000..98487492172
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmFailure.hbs
@@ -0,0 +1,36 @@
+
+
+
+
+ {{titleByStatus 'failure' tasksByStatus.failure.tasks}}
+
+
+
+
+{{#each tasksByStatus.failure.tasks}}
+
+
+
+ {{#if uuid}}
+ {{name}}
+
+ - UUID: {{uuid}}
+ - Type: {{taskLog.data.type}}
+ {{>reportTemporalData end=taskLog.end start=taskLog.start}}
+ {{>reportWarnings task=taskLog}}
+ - Error: {{taskLog.result.message}}
+
+ {{else}}
+ {{>vmText formatDate=../formatDate}}
+ {{#if taskLog.result}}
+ Error: {{taskLog.result.message}}
+
+ {{else}}
+
+ {{>vmSubText formatDate=../formatDate}}
+ {{/if}}
+ {{/if}}
+
+
+
+{{/each}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmInterrupted.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmInterrupted.hbs
new file mode 100644
index 00000000000..6c446e80d3b
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmInterrupted.hbs
@@ -0,0 +1,20 @@
+
+
+
+
+ {{titleByStatus 'interrupted' tasksByStatus.interrupted.tasks}}
+
+
+
+
+{{#each tasksByStatus.interrupted.tasks}}
+
+
+
+ {{>vmText formatDate=../formatDate}}
+
+
+
+
+ {{>vmSubText formatDate=../formatDate}}
+{{/each}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmSkipped.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmSkipped.hbs
new file mode 100644
index 00000000000..6760c1c1c07
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmSkipped.hbs
@@ -0,0 +1,20 @@
+
+
+
+
+ {{titleByStatus 'skipped' tasksByStatus.skipped.tasks}}
+
+
+
+
+{{#each tasksByStatus.skipped.tasks}}
+
+
+
+ {{>vmText formatDate=../formatDate}}
+ Reason: {{message}}
+
+
+
+
+{{/each}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmSubTask.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmSubTask.hbs
new file mode 100644
index 00000000000..25367d9d262
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmSubTask.hbs
@@ -0,0 +1,31 @@
+{{#if subTaskLog}}
+
+
+
+ {{title}} ({{id}}) {{getIcon subTaskLog.status}}
+
+ {{>reportTemporalData end=subTaskLog.end start=subTaskLog.start}}
+ {{>reportWarnings task=subTaskLog}}
+ {{>reportError task=subTaskLog}}
+
+
+
+
+{{else}}
+
+
+
+ {{operationLog.message}} {{getIcon operationLog.status}}
+
+ {{>reportTemporalData end=operationLog.end start=operationLog.start}}
+ {{#if operationLog.result.size}}
+ - Size: {{formatSize operationLog.result.size}}
+ - Speed: {{formatSpeed operationLog.result.size operationLog.start operationLog.end}}
+ {{/if}}
+ {{>reportWarnings task=operationLog}}
+ {{>reportError task=operationLog}}
+
+
+
+
+{{/if}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmSubText.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmSubText.hbs
new file mode 100644
index 00000000000..d4a04fc4440
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmSubText.hbs
@@ -0,0 +1,48 @@
+{{#each snapshotSubtasks}}
+
+
+
+ ➤ Snapshot {{getIcon subTaskLog.status}}
+
+
+
+
+
+
+
+
+ {{>reportTemporalData end=subTaskLog.end start=subTaskLog.start formatDate=../formatDate}}
+
+
+
+
+{{/each}}
+
+{{#if srsSubTasks}}
+
+
+
+
+ ➤ SRs
+
+
+
+
+ {{#each srsSubTasks}}
+ {{>vmSubTask formatDate=../formatDate}}
+ {{/each}}
+{{/if}}
+
+{{#if remotesSubTasks}}
+
+
+
+ ➤ Remotes
+
+
+
+
+ {{#each remotesSubTasks}}
+ {{>vmSubTask formatDate=../formatDate}}
+ {{/each}}
+{{/if}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmSuccess.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmSuccess.hbs
new file mode 100644
index 00000000000..05ad6eb1f81
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmSuccess.hbs
@@ -0,0 +1,20 @@
+
+
+
+
+ {{titleByStatus 'success' tasksByStatus.success.tasks}}
+
+
+
+
+{{#each tasksByStatus.success.tasks}}
+
+
+
+ {{>vmText formatDate=../formatDate}}
+
+
+
+
+ {{>vmSubText formatDate=../formatDate}}
+{{/each}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/partials/vmText.hbs b/packages/xo-server-backup-reports/templates/mjml/partials/vmText.hbs
new file mode 100644
index 00000000000..3b3a43a51c8
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/partials/vmText.hbs
@@ -0,0 +1,12 @@
+
+{{#if vm}}
+{{vm.name_label}}
+
+ - UUID: {{vm.uuid}}
+{{else}}
+VM not found
+
+ - UUID: {{taskLog.data.id}}
+{{/if}}
+{{>reportTemporalData end=taskLog.end start=taskLog.start}}
+{{>reportWarnings task=taskLog}}
diff --git a/packages/xo-server-backup-reports/templates/mjml/transform.js b/packages/xo-server-backup-reports/templates/mjml/transform.js
new file mode 100644
index 00000000000..0af10ad353a
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/transform.js
@@ -0,0 +1,7 @@
+'use strict'
+
+const mjml2html = require('mjml')
+
+exports.transform = async function transform(source) {
+ return { html: mjml2html(source).html }
+}
diff --git a/packages/xo-server-backup-reports/templates/mjml/vm.hbs b/packages/xo-server-backup-reports/templates/mjml/vm.hbs
new file mode 100644
index 00000000000..83d4d40eb25
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/vm.hbs
@@ -0,0 +1,60 @@
+
+ {{>mjmlHeaders}}
+
+
+
+
+
+ VM Backup report
+
+
+
+
+
+
+
+
+
+
+ Global status : {{log.status}} {{getIcon log.status}}
+
+ - Job ID: {{log.jobId}}
+ - Run ID: {{log.id}}
+ - Mode: {{log.data.mode}}
+ {{>reportTemporalData end=log.end start=log.start}}
+ {{#if log.tasks}}
+ -
+ Successes: {{#if tasksByStatus.success.tasks.length ~}}
+ {{tasksByStatus.success.tasks.length}} {{~else~}} 0 {{~/if}} / {{log.tasks.length}}
+
+ {{#if globalTransferSize}}
+ - Transfer size: {{formatSize globalTransferSize}}
+ {{/if}}
+ {{#if globalMergeSize}}
+ - Merge size: {{formatSize globalMergeSize}}
+ {{/if}}
+ {{/if}} {{>reportError task=log}} {{>reportWarnings task=log}}
+
+
+
+
+
+ {{#if tasksByStatus.failure.tasks}}
+ {{>vmFailure}}
+ {{/if}}
+ {{#if tasksByStatus.skipped.tasks}}
+ {{>vmSkipped}}
+ {{/if}}
+ {{#if tasksByStatus.interrupted.tasks}}
+ {{>vmInterrupted}}
+ {{/if}}
+ {{#if tasksByStatus.success.tasks}}
+ {{>vmSuccess}}
+ {{/if}}
+
+ {{>mjmlFooter}}
+
+
+
diff --git a/packages/xo-server-backup-reports/templates/mjml/vmSubject.hbs b/packages/xo-server-backup-reports/templates/mjml/vmSubject.hbs
new file mode 100644
index 00000000000..868c9e765ce
--- /dev/null
+++ b/packages/xo-server-backup-reports/templates/mjml/vmSubject.hbs
@@ -0,0 +1 @@
+[Xen Orchestra] {{{log.status}}} − Backup report for {{{jobName}}} {{{getIcon log.status}}}
diff --git a/yarn.lock b/yarn.lock
index d2f260f0fa2..c1d36e030e7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1787,7 +1787,7 @@
dependencies:
regenerator-runtime "^0.14.0"
-"@babel/runtime@^7.14.0":
+"@babel/runtime@^7.14.0", "@babel/runtime@^7.23.9":
version "7.24.7"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12"
integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==
@@ -2821,6 +2821,11 @@
dependencies:
pako "^1.0.3"
+"@one-ini/wasm@0.1.1":
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323"
+ integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==
+
"@peculiar/asn1-cms@^2.3.8":
version "2.3.8"
resolved "https://registry.yarnpkg.com/@peculiar/asn1-cms/-/asn1-cms-2.3.8.tgz#16de1b86e5f9f79ac838f392283a4b47e6d396a5"
@@ -7531,7 +7536,7 @@ cheerio-select@^2.1.0:
domhandler "^5.0.3"
domutils "^3.0.1"
-cheerio@^1.0.0-rc.3:
+cheerio@1.0.0-rc.12, cheerio@^1.0.0-rc.12, cheerio@^1.0.0-rc.3:
version "1.0.0-rc.12"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.12.tgz#788bf7466506b1c6bf5fae51d24a2c4d62e47683"
integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==
@@ -7553,7 +7558,7 @@ child-process-promise@^2.0.3:
node-version "^1.0.0"
promise-polyfill "^6.0.1"
-"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.5.1, chokidar@^3.5.3, chokidar@^3.6.0:
+"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.4.0, chokidar@^3.4.1, chokidar@^3.5.1, chokidar@^3.5.3, chokidar@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
@@ -7979,11 +7984,21 @@ commander@2.17.x:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+commander@^10.0.0:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
+ integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
+
commander@^4.0.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+commander@^6.1.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
+ integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
+
commander@~2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
@@ -8057,6 +8072,14 @@ confbox@^0.1.7:
resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579"
integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==
+config-chain@^1.1.13:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
+ integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
+ dependencies:
+ ini "^1.3.4"
+ proto-list "~1.2.1"
+
configstore@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
@@ -9389,7 +9412,7 @@ detect-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
-detect-node@^2.0.4:
+detect-node@2.1.0, detect-node@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
@@ -9604,6 +9627,13 @@ domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+domhandler@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a"
+ integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==
+ dependencies:
+ domelementtype "^2.0.1"
+
domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
@@ -9626,7 +9656,7 @@ domutils@^1.7.0:
dom-serializer "0"
domelementtype "1"
-domutils@^2.5.2, domutils@^2.8.0:
+domutils@^2.4.2, domutils@^2.5.2, domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
@@ -9635,7 +9665,7 @@ domutils@^2.5.2, domutils@^2.8.0:
domelementtype "^2.2.0"
domhandler "^4.2.0"
-domutils@^3.0.1:
+domutils@^3.0.1, domutils@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
@@ -9734,6 +9764,16 @@ echarts@^5.4.3:
tslib "2.3.0"
zrender "5.5.0"
+editorconfig@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-1.0.4.tgz#040c9a8e9a6c5288388b87c2db07028aa89f53a3"
+ integrity sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==
+ dependencies:
+ "@one-ini/wasm" "0.1.1"
+ commander "^10.0.0"
+ minimatch "9.0.1"
+ semver "^7.5.3"
+
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -10279,6 +10319,11 @@ escape-goat@^2.0.0:
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
+escape-goat@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-3.0.0.tgz#e8b5fb658553fe8a3c4959c316c6ebb8c842b19c"
+ integrity sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==
+
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@@ -12733,6 +12778,16 @@ htmlescape@^1.1.0:
resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351"
integrity sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==
+htmlparser2@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-5.0.1.tgz#7daa6fc3e35d6107ac95a4fc08781f091664f6e7"
+ integrity sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^3.3.0"
+ domutils "^2.4.2"
+ entities "^2.0.0"
+
htmlparser2@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
@@ -12753,6 +12808,16 @@ htmlparser2@^8.0.0, htmlparser2@^8.0.1:
domutils "^3.0.1"
entities "^4.4.0"
+htmlparser2@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.1.0.tgz#cdb498d8a75a51f739b61d3f718136c369bc8c23"
+ integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+ domutils "^3.1.0"
+ entities "^4.5.0"
+
http-assert@^1.3.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f"
@@ -14424,11 +14489,27 @@ jiti@^1.19.1:
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de"
integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==
+js-beautify@^1.6.14:
+ version "1.15.1"
+ resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.15.1.tgz#4695afb508c324e1084ee0b952a102023fc65b64"
+ integrity sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==
+ dependencies:
+ config-chain "^1.1.13"
+ editorconfig "^1.0.4"
+ glob "^10.3.3"
+ js-cookie "^3.0.5"
+ nopt "^7.2.0"
+
js-cookie@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
+js-cookie@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
+ integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
+
js-md4@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5"
@@ -14650,6 +14731,17 @@ jstransformer@1.0.0:
object.assign "^4.1.4"
object.values "^1.1.6"
+juice@^10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/juice/-/juice-10.0.0.tgz#c6b717ded8be4b969f12503ac9cfbd2604d35937"
+ integrity sha512-9f68xmhGrnIi6DBkiiP3rUrQN33SEuaKu1+njX6VgMP+jwZAsnT33WIzlrWICL9matkhYu3OyrqSUP55YTIdGg==
+ dependencies:
+ cheerio "^1.0.0-rc.12"
+ commander "^6.1.0"
+ mensch "^0.3.4"
+ slick "^1.12.2"
+ web-resource-inliner "^6.0.1"
+
just-debounce@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf"
@@ -15769,6 +15861,11 @@ memorystream@^0.3.1:
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==
+mensch@^0.3.4:
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/mensch/-/mensch-0.3.4.tgz#770f91b46cb16ea5b204ee735768c3f0c491fecd"
+ integrity sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==
+
meow@^12.0.1:
version "12.1.1"
resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6"
@@ -15889,7 +15986,7 @@ mime@1.6.0, mime@^1.4.1:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-mime@^2.0.3, mime@^2.4.4:
+mime@^2.0.3, mime@^2.4.4, mime@^2.4.6:
version "2.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
@@ -15953,6 +16050,13 @@ minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
+minimatch@9.0.1:
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.1.tgz#8a555f541cf976c622daf078bb28f29fb927c253"
+ integrity sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==
+ dependencies:
+ brace-expansion "^2.0.1"
+
minimatch@9.0.3:
version "9.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
@@ -16091,6 +16195,339 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
+mjml-accordion@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-accordion/-/mjml-accordion-4.15.3.tgz#10e4c4297df3ad8dfa709fc64e887f89bfbff0a8"
+ integrity sha512-LPNVSj1LyUVYT9G1gWwSw3GSuDzDsQCu0tPB2uDsq4VesYNnU6v3iLCQidMiR6azmIt13OEozG700ygAUuA6Ng==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-body@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-body/-/mjml-body-4.15.3.tgz#8885b2921f6daa1a287e8aea0924ee1fc4aaf222"
+ integrity sha512-7pfUOVPtmb0wC+oUOn4xBsAw4eT5DyD6xqaxj/kssu6RrFXOXgJaVnDPAI9AzIvXJ/5as9QrqRGYAddehwWpHQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-button@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-button/-/mjml-button-4.15.3.tgz#34baf2d7fbf77a5febe6993e311103723279adbd"
+ integrity sha512-79qwn9AgdGjJR1vLnrcm2rq2AsAZkKC5JPwffTMG+Nja6zGYpTDZFZ56ekHWr/r1b5WxkukcPj2PdevUug8c+Q==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-carousel@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-carousel/-/mjml-carousel-4.15.3.tgz#fe82d2c4c8020ef14f3b360316c670f7da294193"
+ integrity sha512-3ju6I4l7uUhPRrJfN3yK9AMsfHvrYbRkcJ1GRphFHzUj37B2J6qJOQUpzA547Y4aeh69TSb7HFVf1t12ejQxVw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-cli@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-cli/-/mjml-cli-4.15.3.tgz#5638f1919c952d224f51970a2fbf3141dee6d487"
+ integrity sha512-+V2TDw3tXUVEptFvLSerz125C2ogYl8klIBRY1m5BHd4JvGVf3yhx8N3PngByCzA6PGcv/eydGQN+wy34SHf0Q==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ chokidar "^3.0.0"
+ glob "^10.3.10"
+ html-minifier "^4.0.0"
+ js-beautify "^1.6.14"
+ lodash "^4.17.21"
+ minimatch "^9.0.3"
+ mjml-core "4.15.3"
+ mjml-migrate "4.15.3"
+ mjml-parser-xml "4.15.3"
+ mjml-validator "4.15.3"
+ yargs "^17.7.2"
+
+mjml-column@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-column/-/mjml-column-4.15.3.tgz#ffc538f6b87a7340697f88600330110a40f82c05"
+ integrity sha512-hYdEFdJGHPbZJSEysykrevEbB07yhJGSwfDZEYDSbhQQFjV2tXrEgYcFD5EneMaowjb55e3divSJxU4c5q4Qgw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-core@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-core/-/mjml-core-4.15.3.tgz#96c30f49340b95bb9c825a6479557cc9ad1af6c6"
+ integrity sha512-Dmwk+2cgSD9L9GmTbEUNd8QxkTZtW9P7FN/ROZW/fGZD6Hq6/4TB0zEspg2Ow9eYjZXO2ofOJ3PaQEEShKV0kQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ cheerio "1.0.0-rc.12"
+ detect-node "^2.0.4"
+ html-minifier "^4.0.0"
+ js-beautify "^1.6.14"
+ juice "^10.0.0"
+ lodash "^4.17.21"
+ mjml-migrate "4.15.3"
+ mjml-parser-xml "4.15.3"
+ mjml-validator "4.15.3"
+
+mjml-divider@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-divider/-/mjml-divider-4.15.3.tgz#2aadaf7e9955a9d9473f7093598f933aa289c683"
+ integrity sha512-vh27LQ9FG/01y0b9ntfqm+GT5AjJnDSDY9hilss2ixIUh0FemvfGRfsGVeV5UBVPBKK7Ffhvfqc7Rciob9Spzw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-group@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-group/-/mjml-group-4.15.3.tgz#7e4418d7d4b5d5d5e4d6af9865c25d6d358a7f75"
+ integrity sha512-HSu/rKnGZVKFq3ciT46vi1EOy+9mkB0HewO4+P6dP/Y0UerWkN6S3UK11Cxsj0cAp0vFwkPDCdOeEzRdpFEkzA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-attributes@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-attributes/-/mjml-head-attributes-4.15.3.tgz#4c81e561982fca2657bf3dda7576fcafec778b66"
+ integrity sha512-2ISo0r5ZKwkrvJgDou9xVPxxtXMaETe2AsAA02L89LnbB2KC0N5myNsHV0sEysTw9+CfCmgjAb0GAI5QGpxKkQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-breakpoint@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-breakpoint/-/mjml-head-breakpoint-4.15.3.tgz#be1fbe6b4f6cd77f7f666b2cb9e48e81f727b74f"
+ integrity sha512-Eo56FA5C2v6ucmWQL/JBJ2z641pLOom4k0wP6CMZI2utfyiJ+e2Uuinj1KTrgDcEvW4EtU9HrfAqLK9UosLZlg==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-font@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-font/-/mjml-head-font-4.15.3.tgz#0340872d0ffe9e29044d66ede452575cb7da3ddf"
+ integrity sha512-CzV2aDPpiNIIgGPHNcBhgyedKY4SX3BJoTwOobSwZVIlEA6TAWB4Z9WwFUmQqZOgo1AkkiTHPZQvGcEhFFXH6g==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-html-attributes@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-html-attributes/-/mjml-head-html-attributes-4.15.3.tgz#852710724b976fac7aabd648f5f9770bfa1e21e5"
+ integrity sha512-MDNDPMBOgXUZYdxhosyrA2kudiGO8aogT0/cODyi2Ed9o/1S7W+je11JUYskQbncqhWKGxNyaP4VWa+6+vUC/g==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-preview@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-preview/-/mjml-head-preview-4.15.3.tgz#710ce159974bf2924edb7f920dd05280a433afd3"
+ integrity sha512-J2PxCefUVeFwsAExhrKo4lwxDevc5aKj888HBl/wN4EuWOoOg06iOGCxz4Omd8dqyFsrqvbBuPqRzQ+VycGmaA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-style@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-style/-/mjml-head-style-4.15.3.tgz#66a9a3926888681578c2550c7444e4f8cbddfda3"
+ integrity sha512-9J+JuH+mKrQU65CaJ4KZegACUgNIlYmWQYx3VOBR/tyz+8kDYX7xBhKJCjQ1I4wj2Tvga3bykd89Oc2kFZ5WOw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head-title@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head-title/-/mjml-head-title-4.15.3.tgz#ccbd11a7771965f5ac5f3069f6c4f74668c9e6ea"
+ integrity sha512-IM59xRtsxID4DubQ0iLmoCGXguEe+9BFG4z6y2xQDrscIa4QY3KlfqgKGT69ojW+AVbXXJPEVqrAi4/eCsLItQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-head@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-head/-/mjml-head-4.15.3.tgz#3e7311af0de4911dd167c877cf04d4291206cd2f"
+ integrity sha512-o3mRuuP/MB5fZycjD3KH/uXsnaPl7Oo8GtdbJTKtH1+O/3pz8GzGMkscTKa97l03DAG2EhGrzzLcU2A6eshwFw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-hero@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-hero/-/mjml-hero-4.15.3.tgz#c51d9f6d1f37acf7e35d827ce3116f8a4aaf9037"
+ integrity sha512-9cLAPuc69yiuzNrMZIN58j+HMK1UWPaq2i3/Fg2ZpimfcGFKRcPGCbEVh0v+Pb6/J0+kf8yIO0leH20opu3AyQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-image@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-image/-/mjml-image-4.15.3.tgz#e652a4b18663c7d93cc22d88eed45f3fdb9c82ea"
+ integrity sha512-g1OhSdofIytE9qaOGdTPmRIp7JsCtgO0zbsn1Fk6wQh2gEL55Z40j/VoghslWAWTgT2OHFdBKnMvWtN6U5+d2Q==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-migrate@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-migrate/-/mjml-migrate-4.15.3.tgz#65e2b335a2ffc7e29e09f96793961d0e8f081d98"
+ integrity sha512-sr/+35RdxZroNQVegjpfRHJ5hda9XCgaS4mK2FGO+Mb1IUevKfeEPII3F/cHDpNwFeYH3kAgyqQ22ClhGLWNBA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ js-beautify "^1.6.14"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+ mjml-parser-xml "4.15.3"
+ yargs "^17.7.2"
+
+mjml-navbar@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-navbar/-/mjml-navbar-4.15.3.tgz#c9805a98f24a475dd3feece58e690838c075fdff"
+ integrity sha512-VsKH/Jdlf8Yu3y7GpzQV5n7JMdpqvZvTSpF6UQXL0PWOm7k6+LX+sCZimOfpHJ+wCaaybpxokjWZ71mxOoCWoA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-parser-xml@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-parser-xml/-/mjml-parser-xml-4.15.3.tgz#8b94550dbe0d16155ea6cd1fb34bc53dba6f59ed"
+ integrity sha512-Tz0UX8/JVYICLjT+U8J1f/TFxIYVYjzZHeh4/Oyta0pLpRLeZlxEd71f3u3kdnulCKMP4i37pFRDmyLXAlEuLw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ detect-node "2.1.0"
+ htmlparser2 "^9.1.0"
+ lodash "^4.17.15"
+
+mjml-preset-core@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-preset-core/-/mjml-preset-core-4.15.3.tgz#d4972292b7db42b51d08feb1104ad23ee5d3b87f"
+ integrity sha512-1zZS8P4O0KweWUqNS655+oNnVMPQ1Rq1GaZq5S9JfwT1Vh/m516lSmiTW9oko6gGHytt5s6Yj6oOeu5Zm8FoLw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ mjml-accordion "4.15.3"
+ mjml-body "4.15.3"
+ mjml-button "4.15.3"
+ mjml-carousel "4.15.3"
+ mjml-column "4.15.3"
+ mjml-divider "4.15.3"
+ mjml-group "4.15.3"
+ mjml-head "4.15.3"
+ mjml-head-attributes "4.15.3"
+ mjml-head-breakpoint "4.15.3"
+ mjml-head-font "4.15.3"
+ mjml-head-html-attributes "4.15.3"
+ mjml-head-preview "4.15.3"
+ mjml-head-style "4.15.3"
+ mjml-head-title "4.15.3"
+ mjml-hero "4.15.3"
+ mjml-image "4.15.3"
+ mjml-navbar "4.15.3"
+ mjml-raw "4.15.3"
+ mjml-section "4.15.3"
+ mjml-social "4.15.3"
+ mjml-spacer "4.15.3"
+ mjml-table "4.15.3"
+ mjml-text "4.15.3"
+ mjml-wrapper "4.15.3"
+
+mjml-raw@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-raw/-/mjml-raw-4.15.3.tgz#ab771a3d9b5b05583ff90653bf7ca74ec96ffc20"
+ integrity sha512-IGyHheOYyRchBLiAEgw3UM11kFNmBSMupu2BDdejC6ZiDhEAdG+tyERlsCwDPYtXanvFpGWULIu3XlsUPc+RZw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-section@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-section/-/mjml-section-4.15.3.tgz#ba2b524449b18a4fbbdf05c223a0627e02afa7a9"
+ integrity sha512-JfVPRXH++Hd933gmQfG8JXXCBCR6fIzC3DwiYycvanL/aW1cEQ2EnebUfQkt5QzlYjOkJEH+JpccAsq3ln6FZQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-social@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-social/-/mjml-social-4.15.3.tgz#8d1ac1dfd3c56077e1106ead283a40878a2c32d9"
+ integrity sha512-7sD5FXrESOxpT9Z4Oh36bS6u/geuUrMP1aCg2sjyAwbPcF1aWa2k9OcatQfpRf6pJEhUZ18y6/WBBXmMVmSzXg==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-spacer@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-spacer/-/mjml-spacer-4.15.3.tgz#9a2a4b9d51df2e9cae9fbe9848fd722ef0dfd335"
+ integrity sha512-3B7Qj+17EgDdAtZ3NAdMyOwLTX1jfmJuY7gjyhS2HtcZAmppW+cxqHUBwCKfvSRgTQiccmEvtNxaQK+tfyrZqA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-table@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-table/-/mjml-table-4.15.3.tgz#702271761e450172bd5dda9ffcb2faefed3f5db0"
+ integrity sha512-FLx7DcRKTdKdcOCbMyBaeudeHaHpwPveRrBm6WyQe3LXx6FfdmOh59i71/16LFQMgBOD3N4/UJkzxLzlTJzMqQ==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-text@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-text/-/mjml-text-4.15.3.tgz#045ca711b0c18d2ba163c5a9f296a0c7ed82dbfc"
+ integrity sha512-+C0hxCmw9kg0XzT6vhE5mFkK6y225nC8UEQcN94K0fBCjPKkM+HqZMwGX205fzdGRi+Bxa55b/VhrIVwdv+8vw==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+
+mjml-validator@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-validator/-/mjml-validator-4.15.3.tgz#c7934ca66ff41fa7293927b1328cfbafa8268ffb"
+ integrity sha512-Xb72KdqRwjv/qM2rJpV22syyP2N3cRQ9VVDrN6u2FSzLq02buFNxmSPJ7CKhat3PrUNdVHU75KZwOf/tz4UEhA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+
+mjml-wrapper@4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml-wrapper/-/mjml-wrapper-4.15.3.tgz#6526824608514561376ecfdab079275f53cc8706"
+ integrity sha512-ditsCijeHJrmBmObtJmQ18ddLxv5oPyMTdPU8Di8APOnD2zPk7Z4UAuJSl7HXB45oFiivr3MJf4koFzMUSZ6Gg==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ lodash "^4.17.21"
+ mjml-core "4.15.3"
+ mjml-section "4.15.3"
+
+mjml@^4.15.3:
+ version "4.15.3"
+ resolved "https://registry.yarnpkg.com/mjml/-/mjml-4.15.3.tgz#d46996d63e957ae946b2da6ca78fcef5186beee9"
+ integrity sha512-bW2WpJxm6HS+S3Yu6tq1DUPFoTxU9sPviUSmnL7Ua+oVO3WA5ILFWqvujUlz+oeuM+HCwEyMiP5xvKNPENVjYA==
+ dependencies:
+ "@babel/runtime" "^7.23.9"
+ mjml-cli "4.15.3"
+ mjml-core "4.15.3"
+ mjml-migrate "4.15.3"
+ mjml-preset-core "4.15.3"
+ mjml-validator "4.15.3"
+
mkdirp-classic@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
@@ -16451,7 +16888,7 @@ node-fetch@^1.0.1:
encoding "^0.1.11"
is-stream "^1.0.1"
-node-fetch@^2.6.6, node-fetch@^2.6.7:
+node-fetch@^2.6.0, node-fetch@^2.6.6, node-fetch@^2.6.7:
version "2.7.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
@@ -16575,7 +17012,7 @@ nopt@^5.0.0:
dependencies:
abbrev "1"
-nopt@^7.0.0:
+nopt@^7.0.0, nopt@^7.2.0:
version "7.2.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7"
integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==
@@ -18424,6 +18861,11 @@ proper-lockfile@^4.1.2:
retry "^0.12.0"
signal-exit "^3.0.2"
+proto-list@~1.2.1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
+ integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
+
protocol-buffers-encodings@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/protocol-buffers-encodings/-/protocol-buffers-encodings-1.2.0.tgz#39900b85dcff3172a23f15bdf3fda70daa2b38d3"
@@ -20465,6 +20907,11 @@ slice-ansi@^7.0.0:
ansi-styles "^6.2.1"
is-fullwidth-code-point "^5.0.0"
+slick@^1.12.2:
+ version "1.12.2"
+ resolved "https://registry.yarnpkg.com/slick/-/slick-1.12.2.tgz#bd048ddb74de7d1ca6915faa4a57570b3550c2d7"
+ integrity sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==
+
smart-buffer@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
@@ -20961,7 +21408,7 @@ string-length@^6.0.0:
dependencies:
strip-ansi "^7.1.0"
-"string-width-cjs@npm:string-width@^4.2.0":
+"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -20979,15 +21426,6 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
-"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
string-width@^3.0.0, string-width@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
@@ -21104,7 +21542,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -21132,13 +21570,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
dependencies:
ansi-regex "^4.1.0"
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
strip-ansi@^7.0.1, strip-ansi@^7.1.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -22547,6 +22978,11 @@ v8flags@^3.1.1, v8flags@^3.2.0:
dependencies:
homedir-polyfill "^1.0.1"
+valid-data-url@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/valid-data-url/-/valid-data-url-3.0.1.tgz#826c1744e71b5632e847dd15dbd45b9fb38aa34f"
+ integrity sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==
+
validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
@@ -22968,6 +23404,18 @@ wcwidth@^1.0.1:
dependencies:
defaults "^1.0.3"
+web-resource-inliner@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz#df0822f0a12028805fe80719ed52ab6526886e02"
+ integrity sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==
+ dependencies:
+ ansi-colors "^4.1.1"
+ escape-goat "^3.0.0"
+ htmlparser2 "^5.0.0"
+ mime "^2.4.6"
+ node-fetch "^2.6.0"
+ valid-data-url "^3.0.0"
+
web-streams-polyfill@^3.0.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b"
@@ -23316,7 +23764,7 @@ worker-farm@^1.7.0:
dependencies:
errno "~0.1.7"
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -23351,15 +23799,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"