Added feature to create template from another template.

This commit is contained in:
Tomas Bures 2019-02-18 20:36:44 +00:00
parent 031b346440
commit 8d95f43dbc
5 changed files with 90 additions and 41 deletions

View file

@ -12,12 +12,12 @@ import {
} from '../lib/page'
import {
Button,
ButtonRow,
ButtonRow, CheckBox,
Dropdown,
Form,
FormSendMethod,
InputField,
StaticField,
StaticField, TableSelect,
TextArea,
withForm
} from '../lib/form';
@ -41,6 +41,8 @@ import styles
import {getUrl} from "../lib/urls";
import {TestSendModalDialog} from "./TestSendModalDialog";
import {withComponentMixins} from "../lib/decorator-helpers";
import moment
from 'moment';
@withComponentMixins([
@ -98,6 +100,10 @@ console.log('constructor')
description: '',
namespace: mailtrainConfig.user.namespace,
type: mailtrainConfig.editors[0],
fromSourceTemplate: false,
sourceTemplate: null,
text: '',
html: '',
data: {},
@ -122,6 +128,12 @@ console.log('constructor')
state.setIn(['type', 'error'], t('typeMustBeSelected'));
}
if (state.getIn(['fromSourceTemplate', 'value']) && !state.getIn(['sourceTemplate', 'value'])) {
state.setIn(['sourceTemplate', 'error'], t('Source template must not be empty'));
} else {
state.setIn(['sourceTemplate', 'error'], null);
}
validateNamespace(t, state);
if (typeKey) {
@ -255,6 +267,13 @@ console.log('constructor')
typeForm = getTypeForm(this, typeKey, isEdit);
}
const templatesColumns = [
{ data: 1, title: t('name') },
{ data: 2, title: t('description') },
{ data: 3, title: t('type'), render: data => this.templateTypes[data].typeName },
{ data: 4, title: t('created'), render: data => moment(data).fromNow() },
{ data: 5, title: t('namespace') },
];
return (
<div className={this.state.elementInFullscreen ? styles.withElementInFullscreen : ''}>
@ -281,16 +300,25 @@ console.log('constructor')
<InputField id="name" label={t('name')}/>
<TextArea id="description" label={t('description')}/>
{isEdit
?
<StaticField id="type" className={styles.formDisabled} label={t('type')}>
{typeKey && this.templateTypes[typeKey].typeName}
</StaticField>
:
<Dropdown id="type" label={t('type')} options={typeOptions}/>
{!isEdit &&
<CheckBox id="fromSourceTemplate" label={t('template')} text={t('Clone from an existing template')}/>
}
{typeForm}
{this.getFormValue('fromSourceTemplate') ?
<TableSelect key="templateSelect" id="sourceTemplate" withHeader dropdown dataUrl='rest/templates-table' columns={templatesColumns} selectionLabelIndex={1} />
:
<>
{isEdit ?
<StaticField id="type" className={styles.formDisabled} label={t('type')}>
{typeKey && this.templateTypes[typeKey].typeName}
</StaticField>
:
<Dropdown id="type" label={t('type')} options={typeOptions}/>
}
{typeForm}
</>
}
<NamespaceSelect/>

View file

@ -255,11 +255,11 @@ export function getTemplateTypes(t, prefix = '', entityTypeId = ResourceType.TEM
return <StaticField
id={prefix + 'grapesJSSourceType'}
className={styles.formDisabled}
label={t('type')}>{grapesJSSourceTypeLabels[owner.getFormValue(prefix + 'grapesJSSourceType')]}</StaticField>;
label={t('Content')}>{grapesJSSourceTypeLabels[owner.getFormValue(prefix + 'grapesJSSourceType')]}</StaticField>;
} else {
return <Dropdown
id={prefix + 'grapesJSSourceType'}
label={t('type')}
label={t('Content')}
options={grapesJSSourceTypes}/>;
}
},

View file

@ -0,0 +1,32 @@
'use strict';
function convertFileURLs(sourceCustom, fromEntityType, fromEntityId, toEntityType, toEntityId) {
function convertText(text) {
if (text) {
const fromUrl = `/files/${fromEntityType}/file/${fromEntityId}`;
const toUrl = `/files/${toEntityType}/file/${toEntityId}`;
const encodedFromUrl = encodeURIComponent(fromUrl);
const encodedToUrl = encodeURIComponent(toUrl);
text = text.split('[URL_BASE]' + fromUrl).join('[URL_BASE]' + toUrl);
text = text.split('[SANDBOX_URL_BASE]' + fromUrl).join('[SANDBOX_URL_BASE]' + toUrl);
text = text.split('[ENCODED_URL_BASE]' + encodedFromUrl).join('[ENCODED_URL_BASE]' + encodedToUrl);
text = text.split('[ENCODED_SANDBOX_URL_BASE]' + encodedFromUrl).join('[ENCODED_SANDBOX_URL_BASE]' + encodedToUrl);
}
return text;
}
sourceCustom.html = convertText(sourceCustom.html);
sourceCustom.text = convertText(sourceCustom.text);
if (sourceCustom.type === 'mosaico' || sourceCustom.type === 'mosaicoWithFsTemplate') {
sourceCustom.data.model = convertText(sourceCustom.data.model);
sourceCustom.data.model = convertText(sourceCustom.data.model);
sourceCustom.data.metadata = convertText(sourceCustom.data.metadata);
}
}
module.exports.convertFileURLs = convertFileURLs;

View file

@ -20,6 +20,7 @@ const senders = require('../lib/senders');
const {LinkId} = require('./links');
const feedcheck = require('../lib/feedcheck');
const contextHelpers = require('../lib/context-helpers');
const {convertFileURLs} = require('../lib/campaign-content');
const {EntityActivityType, CampaignActivityType} = require('../../shared/activity-log');
const activityLog = require('../lib/activity-log');
@ -430,35 +431,6 @@ async function _validateAndPreprocess(tx, context, entity, isCreate, content) {
}
}
function convertFileURLs(sourceCustom, fromEntityType, fromEntityId, toEntityType, toEntityId) {
function convertText(text) {
if (text) {
const fromUrl = `/files/${fromEntityType}/file/${fromEntityId}`;
const toUrl = `/files/${toEntityType}/file/${toEntityId}`;
const encodedFromUrl = encodeURIComponent(fromUrl);
const encodedToUrl = encodeURIComponent(toUrl);
text = text.split('[URL_BASE]' + fromUrl).join('[URL_BASE]' + toUrl);
text = text.split('[SANDBOX_URL_BASE]' + fromUrl).join('[SANDBOX_URL_BASE]' + toUrl);
text = text.split('[ENCODED_URL_BASE]' + encodedFromUrl).join('[ENCODED_URL_BASE]' + encodedToUrl);
text = text.split('[ENCODED_SANDBOX_URL_BASE]' + encodedFromUrl).join('[ENCODED_SANDBOX_URL_BASE]' + encodedToUrl);
}
return text;
}
sourceCustom.html = convertText(sourceCustom.html);
sourceCustom.text = convertText(sourceCustom.text);
if (sourceCustom.type === 'mosaico' || sourceCustom.type === 'mosaicoWithFsTemplate') {
sourceCustom.data.model = convertText(sourceCustom.data.model);
sourceCustom.data.model = convertText(sourceCustom.data.model);
sourceCustom.data.metadata = convertText(sourceCustom.data.metadata);
}
}
async function _createTx(tx, context, entity, content) {
return await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'namespace', entity.namespace, 'createCampaign');

View file

@ -10,6 +10,7 @@ const shares = require('./shares');
const reports = require('./reports');
const files = require('./files');
const dependencyHelpers = require('../lib/dependency-helpers');
const {convertFileURLs} = require('../lib/campaign-content');
const allowedKeys = new Set(['name', 'description', 'type', 'data', 'html', 'text', 'namespace']);
@ -57,6 +58,15 @@ async function create(context, entity) {
return await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'namespace', entity.namespace, 'createTemplate');
if (entity.fromSourceTemplate) {
const template = await getByIdTx(tx, context, entity.sourceTemplate, false);
entity.type = template.type;
entity.data = template.data;
entity.html = template.html;
entity.text = template.text;
}
await _validateAndPreprocess(tx, entity);
const ids = await tx('templates').insert(filterObject(entity, allowedKeys));
@ -64,6 +74,13 @@ async function create(context, entity) {
await shares.rebuildPermissionsTx(tx, { entityTypeId: 'template', entityId: id });
if (entity.fromSourceTemplate) {
await files.copyAllTx(tx, context, 'template', 'file', entity.sourceTemplate, 'template', 'file', id);
convertFileURLs(entity, 'template', entity.sourceTemplate, 'template', id);
await tx('templates').update(filterObject(entity, allowedKeys)).where('id', id);
}
return id;
});
}