Added confirmations for unsubscribe, blacklist and remove from blacklist

This commit is contained in:
Tomas Bures 2018-11-22 11:31:16 +01:00
parent aeaaf116d7
commit b058169e12
25 changed files with 290 additions and 228 deletions

View file

@ -7,8 +7,13 @@ import {withAsyncErrorHandler, withErrorHandling} from "../lib/error-handling";
import {Table} from "../lib/table"; import {Table} from "../lib/table";
import {ButtonRow, Form, InputField, withForm, FormSendMethod} from "../lib/form"; import {ButtonRow, Form, InputField, withForm, FormSendMethod} from "../lib/form";
import {Button, Icon} from "../lib/bootstrap-components"; import {Button, Icon} from "../lib/bootstrap-components";
import axios from "../lib/axios"; import axios, {HTTPMethod} from "../lib/axios";
import {getUrl} from "../lib/urls"; import {getUrl} from "../lib/urls";
import {
tableAddRestActionButton,
tableRestActionDialogInit,
tableRestActionDialogRender
} from "../lib/modals";
@withTranslation() @withTranslation()
@withForm @withForm
@ -22,6 +27,7 @@ export default class List extends Component {
const t = props.t; const t = props.t;
this.state = {}; this.state = {};
tableRestActionDialogInit(this);
this.initForm({ this.initForm({
serverValidation: { serverValidation: {
@ -73,7 +79,7 @@ export default class List extends Component {
this.enableForm(); this.enableForm();
this.clearFormStatusMessage(); this.clearFormStatusMessage();
this.blacklistTable.refresh(); this.table.refresh();
} else { } else {
this.enableForm(); this.enableForm();
@ -85,29 +91,36 @@ export default class List extends Component {
this.clearFields(); this.clearFields();
} }
@withAsyncErrorHandler
async deleteBlacklisted(email) {
await axios.delete(getUrl(`rest/blacklist/${email}`));
this.blacklistTable.refresh();
}
render() { render() {
const t = this.props.t; const t = this.props.t;
const columns = [ const columns = [
{ data: 0, title: t('email') }, { data: 0, title: t('email') },
{ {
actions: data => [ actions: data => {
{ const actions = [];
label: <Icon icon="remove" title={t('removeFromBlacklist')}/>,
action: () => this.deleteBlacklisted(data[0]) const email = data[0];
}
] tableAddRestActionButton(
actions, this,
{ method: HTTPMethod.DELETE, url: `rest/blacklist/${email}`},
{ icon: 'remove', label: t('removeFromBlacklist') },
t('Confirm Removal From Blacklist'),
t('Are you sure you want to remove {{email}} from the blacklist?', {email}),
t('Removing {{email}} from the blacklist', {email}),
t('{{email}} removed from the blacklist', {email}),
null
);
return actions;
}
} }
]; ];
return ( return (
<div> <div>
{tableRestActionDialogRender(this)}
<Title>{t('blacklist')}</Title> <Title>{t('blacklist')}</Title>
<h3 className="legend">{t('addEmailToBlacklist-1')}</h3> <h3 className="legend">{t('addEmailToBlacklist-1')}</h3>
@ -123,7 +136,7 @@ export default class List extends Component {
<h3 className="legend">{t('blacklistedEmails')}</h3> <h3 className="legend">{t('blacklistedEmails')}</h3>
<Table ref={node => this.blacklistTable = node} withHeader dataUrl="rest/blacklist-table" columns={columns} /> <Table ref={node => this.table = node} withHeader dataUrl="rest/blacklist-table" columns={columns} />
</div> </div>
); );
} }

View file

@ -27,9 +27,9 @@ import {
import {checkPermissions} from "../lib/permissions"; import {checkPermissions} from "../lib/permissions";
import {getCampaignLabels} from "./helpers"; import {getCampaignLabels} from "./helpers";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@withTranslation() @withTranslation()
@ -47,7 +47,7 @@ export default class List extends Component {
this.campaignStatusLabels = campaignStatusLabels; this.campaignStatusLabels = campaignStatusLabels;
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -151,7 +151,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/campaigns/${data[0]}`, data[1], t('deletingCampaign'), t('campaignDeleted'));
return actions; return actions;
} }
@ -160,7 +160,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/campaigns`, t('deletingCampaign'), t('campaignDeleted'))} {tableRestActionDialogRender(this)}
<Toolbar> <Toolbar>
{this.state.createPermitted && {this.state.createPermitted &&
<DropdownMenu className="btn-primary" label={t('createCampaign')}> <DropdownMenu className="btn-primary" label={t('createCampaign')}>

View file

@ -38,7 +38,7 @@ import {
} from "../../../shared/campaigns"; } from "../../../shared/campaigns";
import moment from 'moment'; import moment from 'moment';
import campaignsStyles from "./styles.scss"; import campaignsStyles from "./styles.scss";
import {tableDeleteDialogAddDeleteButton} from "../lib/modals"; import {tableAddDeleteButton} from "../lib/modals";
@withTranslation() @withTranslation()

View file

@ -16,9 +16,9 @@ import {getTriggerTypes} from './helpers';
import {Icon} from "../../lib/bootstrap-components"; import {Icon} from "../../lib/bootstrap-components";
import mailtrainConfig from 'mailtrainConfig'; import mailtrainConfig from 'mailtrainConfig';
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@withTranslation() @withTranslation()
@ -34,7 +34,7 @@ export default class List extends Component {
this.eventLabels = eventLabels; this.eventLabels = eventLabels;
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
static propTypes = { static propTypes = {
@ -66,7 +66,7 @@ export default class List extends Component {
} }
if (this.props.campaign.permissions.includes('manageTriggers')) { if (this.props.campaign.permissions.includes('manageTriggers')) {
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]); tableAddDeleteButton(actions, this, null, `rest/triggers/${this.props.campaign.id}/${data[0]}`, data[1], t('deletingTrigger'), t('triggerDeleted'));
} }
return actions; return actions;
@ -76,7 +76,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/triggers/${this.props.campaign.id}`, t('deletingTrigger'), t('triggerDeleted'))} {tableRestActionDialogRender(this)}
{mailtrainConfig.globalPermissions.setupAutomation && this.props.campaign.permissions.includes('manageTriggers') && {mailtrainConfig.globalPermissions.setupAutomation && this.props.campaign.permissions.includes('manageTriggers') &&
<Toolbar> <Toolbar>
<NavButton linkTo={`/campaigns/${this.props.campaign.id}/triggers/create`} className="btn-primary" icon="plus" label={t('createTrigger')}/> <NavButton linkTo={`/campaigns/${this.props.campaign.id}/triggers/create`} className="btn-primary" icon="plus" label={t('createTrigger')}/>

View file

@ -24,6 +24,7 @@ export class RestActionModalDialog extends Component {
visible: PropTypes.bool.isRequired, visible: PropTypes.bool.isRequired,
actionMethod: PropTypes.func.isRequired, actionMethod: PropTypes.func.isRequired,
actionUrl: PropTypes.string.isRequired, actionUrl: PropTypes.string.isRequired,
actionData: PropTypes.object,
backUrl: PropTypes.string, backUrl: PropTypes.string,
successUrl: PropTypes.string, successUrl: PropTypes.string,
@ -65,7 +66,7 @@ export class RestActionModalDialog extends Component {
owner.setFormStatusMessage('info', props.actionInProgressMsg); owner.setFormStatusMessage('info', props.actionInProgressMsg);
} }
await axios.method(props.actionMethod, getUrl(props.actionUrl)); await axios.method(props.actionMethod, getUrl(props.actionUrl), props.actionData);
if (props.successUrl) { if (props.successUrl) {
this.navigateToWithFlashMessage(props.successUrl, 'success', props.actionDoneMsg); this.navigateToWithFlashMessage(props.successUrl, 'success', props.actionDoneMsg);
@ -96,6 +97,35 @@ export class RestActionModalDialog extends Component {
} }
} }
const entityTypeLabels = {
'namespace': t => t('namespace'),
'list': t => t('list'),
'customForm': t => t('customForms'),
'campaign': t => t('campaign'),
'template': t => t('template'),
'sendConfiguration': t => t('sendConfiguration'),
'report': t => t('report'),
'reportTemplate': t => t('reportTemplate'),
'mosaicoTemplate': t => t('mosaicoTemplate')
};
function _getDependencyErrorMessage(err, t, name) {
return (
<div>
<p>{t('cannoteDeleteNameDueToTheFollowing', {name})}</p>
<ul className={styles.dependenciesList}>
{err.data.dependencies.map(dep =>
dep.link ?
<li key={dep.link}><Link to={dep.link}>{entityTypeLabels[dep.entityTypeId](t)}: {dep.name}</Link></li>
: // if no dep.link is present, it means the user has no permission to view the entity, thus only id without the link is shown
<li key={dep.id}>{entityTypeLabels[dep.entityTypeId](t)}: [{dep.id}]</li>
)}
{err.data.andMore && <li>{t('andMore')}</li>}
</ul>
</div>
);
}
@withTranslation() @withTranslation()
@withPageHelpers @withPageHelpers
@ -103,35 +133,14 @@ export class DeleteModalDialog extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
const t = props.t; const t = props.t;
this.entityTypeLabels = {
'namespace': t('namespace'),
'list': t('list'),
'customForm': t('customForms'),
'campaign': t('campaign'),
'template': t('template'),
'sendConfiguration': t('sendConfiguration'),
'report': t('report'),
'reportTemplate': t('reportTemplate'),
'mosaicoTemplate': t('mosaicoTemplate')
};
} }
static propTypes = { static propTypes = {
visible: PropTypes.bool.isRequired, visible: PropTypes.bool.isRequired,
stateOwner: PropTypes.object.isRequired,
stateOwner: PropTypes.object,
name: PropTypes.string,
deleteUrl: PropTypes.string.isRequired, deleteUrl: PropTypes.string.isRequired,
backUrl: PropTypes.string, backUrl: PropTypes.string,
successUrl: PropTypes.string, successUrl: PropTypes.string,
onBack: PropTypes.func,
onPerformingAction: PropTypes.func,
onSuccess: PropTypes.func,
onFail: PropTypes.func,
deletingMsg: PropTypes.string.isRequired, deletingMsg: PropTypes.string.isRequired,
deletedMsg: PropTypes.string.isRequired deletedMsg: PropTypes.string.isRequired
} }
@ -142,32 +151,13 @@ export class DeleteModalDialog extends Component {
if (err instanceof interoperableErrors.DependencyPresentError) { if (err instanceof interoperableErrors.DependencyPresentError) {
const owner = this.props.stateOwner; const owner = this.props.stateOwner;
const name = this.props.name !== undefined ? this.props.name : (owner ? owner.getFormValue('name') : ''); const name = owner.getFormValue('name');
this.setFlashMessage('danger', this.setFlashMessage('danger', _getDependencyErrorMessage(err, t, name));
<div>
<p>{t('cannoteDeleteNameDueToTheFollowing', {name})}</p>
<ul className={styles.dependenciesList}>
{err.data.dependencies.map(dep =>
dep.link ?
<li key={dep.link}><Link to={dep.link}>{this.entityTypeLabels[dep.entityTypeId]}: {dep.name}</Link></li>
: // if no dep.link is present, it means the user has no permission to view the entity, thus only id without the link is shown
<li key={dep.id}>{this.entityTypeLabels[dep.entityTypeId]}: [{dep.id}]</li>
)}
{err.data.andMore && <li>{t('andMore')}</li>}
</ul>
</div>
);
window.scrollTo(0, 0); // This is to scroll up because the flash message appears on top and it's quite misleading if the delete fails and the message is not in the viewport window.scrollTo(0, 0); // This is to scroll up because the flash message appears on top and it's quite misleading if the delete fails and the message is not in the viewport
if (this.props.onFail) { owner.enableForm();
this.props.onFail(); owner.clearFormStatusMessage();
}
if (owner) {
owner.enableForm();
owner.clearFormStatusMessage();
}
} else { } else {
throw err; throw err;
@ -177,7 +167,7 @@ export class DeleteModalDialog extends Component {
render() { render() {
const t = this.props.t; const t = this.props.t;
const owner = this.props.stateOwner; const owner = this.props.stateOwner;
const name = this.props.name !== undefined ? this.props.name : (owner ? owner.getFormValue('name') : ''); const name = owner.getFormValue('name');
return <RestActionModalDialog return <RestActionModalDialog
title={t('confirmDeletion')} title={t('confirmDeletion')}
@ -188,9 +178,6 @@ export class DeleteModalDialog extends Component {
actionUrl={this.props.deleteUrl} actionUrl={this.props.deleteUrl}
backUrl={this.props.backUrl} backUrl={this.props.backUrl}
successUrl={this.props.successUrl} successUrl={this.props.successUrl}
onBack={this.props.onBack}
onPerformingAction={this.props.onPerformingAction}
onSuccess={this.props.onSuccess}
actionInProgressMsg={this.props.deletingMsg} actionInProgressMsg={this.props.deletingMsg}
actionDoneMsg={this.props.deletedMsg} actionDoneMsg={this.props.deletedMsg}
onErrorAsync={::this.onErrorAsync} onErrorAsync={::this.onErrorAsync}
@ -198,16 +185,36 @@ export class DeleteModalDialog extends Component {
} }
} }
export function tableDeleteDialogInit(owner) { export function tableRestActionDialogInit(owner) {
owner.deleteDialogData = {}; owner.tableRestActionDialogData = {};
owner.state.deleteDialogShown = false; owner.state.tableRestActionDialogShown = false;
} }
export function tableDeleteDialogAddDeleteButton(actions, owner, perms, id, name) {
function _hide(owner, dontRefresh = false) {
owner.tableRestActionDialogData = {};
owner.setState({ tableRestActionDialogShown: false });
if (!dontRefresh) {
owner.table.refresh();
}
}
export function tableAddDeleteButton(actions, owner, perms, deleteUrl, name, deletingMsg, deletedMsg) {
const t = owner.props.t; const t = owner.props.t;
async function onErrorAsync(err) {
if (err instanceof interoperableErrors.DependencyPresentError) {
owner.setFlashMessage('danger', _getDependencyErrorMessage(err, t, name));
window.scrollTo(0, 0); // This is to scroll up because the flash message appears on top and it's quite misleading if the delete fails and the message is not in the viewport
_hide(owner);
} else {
throw err;
}
}
if (!perms || perms.includes('delete')) { if (!perms || perms.includes('delete')) {
if (owner.deleteDialogData.id) { if (owner.tableRestActionDialogData.shown) {
actions.push({ actions.push({
label: <Icon className={styles.iconDisabled} icon="remove" title={t('delete')}/> label: <Icon className={styles.iconDisabled} icon="remove" title={t('delete')}/>
}); });
@ -215,10 +222,21 @@ export function tableDeleteDialogAddDeleteButton(actions, owner, perms, id, name
actions.push({ actions.push({
label: <Icon icon="remove" title={t('delete')}/>, label: <Icon icon="remove" title={t('delete')}/>,
action: () => { action: () => {
owner.deleteDialogData = {name, id}; owner.tableRestActionDialogData = {
shown: true,
title: t('confirmDeletion'),
message:t('areYouSureYouWantToDeleteName?', {name}),
httpMethod: HTTPMethod.DELETE,
actionUrl: deleteUrl,
actionInProgressMsg: deletingMsg,
actionDoneMsg: deletedMsg,
onErrorAsync: onErrorAsync
};
owner.setState({ owner.setState({
deleteDialogShown: true tableRestActionDialogShown: true
}); });
owner.table.refresh(); owner.table.refresh();
} }
}); });
@ -226,24 +244,55 @@ export function tableDeleteDialogAddDeleteButton(actions, owner, perms, id, name
} }
} }
export function tableDeleteDialogRender(owner, deleteUrlBase, deletingMsg, deletedMsg) { export function tableAddRestActionButton(actions, owner, action, button, title, message, actionInProgressMsg, actionDoneMsg, onErrorAsync) {
function hide() { const t = owner.props.t;
owner.deleteDialogData = {};
owner.setState({ deleteDialogShown: false }); if (owner.tableRestActionDialogData.shown) {
owner.table.refresh(); actions.push({
} label: <Icon className={styles.iconDisabled} icon={button.icon} title={button.label}/>
});
} else {
actions.push({
label: <Icon icon={button.icon} title={button.label}/>,
action: () => {
owner.tableRestActionDialogData = {
shown: true,
title: title,
message: message,
httpMethod: action.method,
actionUrl: action.url,
actionData: action.data,
actionInProgressMsg: actionInProgressMsg,
actionDoneMsg: actionDoneMsg,
onErrorAsync: onErrorAsync
};
owner.setState({
tableRestActionDialogShown: true
});
owner.table.refresh();
}
});
}
}
export function tableRestActionDialogRender(owner) {
const data = owner.tableRestActionDialogData;
return <RestActionModalDialog
title={data.title || ''}
message={data.message || ''}
visible={owner.state.tableRestActionDialogShown}
actionMethod={data.httpMethod || HTTPMethod.POST}
actionUrl={data.actionUrl || ''}
actionData={data.actionData}
onBack={() => _hide(owner)}
onPerformingAction={() => _hide(owner, true)}
onSuccess={() => _hide(owner)}
actionInProgressMsg={data.actionInProgressMsg || ''}
actionDoneMsg={data.actionDoneMsg || ''}
onErrorAsync={data.onErrorAsync}
/>
return (
<DeleteModalDialog
visible={owner.state.deleteDialogShown}
name={owner.deleteDialogData.name}
deleteUrl={deleteUrlBase + '/' + owner.deleteDialogData.id}
onBack={hide}
onPerformingAction={() => owner.setState({ deleteDialogShown: false })}
onSuccess={hide}
onFail={hide}
deletingMsg={deletingMsg}
deletedMsg={deletedMsg}
/>
);
} }

View file

@ -140,7 +140,7 @@
} }
.iconDisabled { .iconDisabled {
color: #888; color: #bf3e11;
} }
.dependenciesList { .dependenciesList {

View file

@ -10,9 +10,9 @@ import {Link} from "react-router-dom";
import {Icon} from "../lib/bootstrap-components"; import {Icon} from "../lib/bootstrap-components";
import {checkPermissions} from "../lib/permissions"; import {checkPermissions} from "../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@withTranslation() @withTranslation()
@ -24,7 +24,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -121,7 +121,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/lists/${data[0]}`, data[1], t('deletingList'), t('listDeleted'));
return actions; return actions;
} }
@ -130,7 +130,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/lists`, t('deletingList'), t('listDeleted'))} {tableRestActionDialogRender(this)}
{this.state.createPermitted && {this.state.createPermitted &&
<Toolbar> <Toolbar>
<NavButton linkTo="/lists/create" className="btn-primary" icon="plus" label={t('createList')}/> <NavButton linkTo="/lists/create" className="btn-primary" icon="plus" label={t('createList')}/>

View file

@ -14,9 +14,9 @@ import {getTriggerTypes} from '../campaigns/triggers/helpers';
import {Icon} from "../lib/bootstrap-components"; import {Icon} from "../lib/bootstrap-components";
import mailtrainConfig from 'mailtrainConfig'; import mailtrainConfig from 'mailtrainConfig';
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@withTranslation() @withTranslation()
@ -32,7 +32,7 @@ export default class List extends Component {
this.eventLabels = eventLabels; this.eventLabels = eventLabels;
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
static propTypes = { static propTypes = {
@ -67,7 +67,7 @@ export default class List extends Component {
} }
if (perms.includes('manageTriggers')) { if (perms.includes('manageTriggers')) {
tableDeleteDialogAddDeleteButton(actions, this, null, campaignId + '/' + data[0], data[1]); tableAddDeleteButton(actions, this, null, `rest/triggers/${campaignId}/${data[0]}`, data[1], t('deletingTrigger'), t('triggerDeleted'));
} }
return actions; return actions;
@ -77,7 +77,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/triggers`, t('deletingTrigger'), t('triggerDeleted'))} {tableRestActionDialogRender(this)}
<Title>{t('triggers')}</Title> <Title>{t('triggers')}</Title>
<Table ref={node => this.table = node} withHeader dataUrl={`rest/triggers-by-list-table/${this.props.list.id}`} columns={columns} /> <Table ref={node => this.table = node} withHeader dataUrl={`rest/triggers-by-list-table/${this.props.list.id}`} columns={columns} />

View file

@ -9,9 +9,9 @@ import { Table } from '../../lib/table';
import { getFieldTypes } from './helpers'; import { getFieldTypes } from './helpers';
import {Icon} from "../../lib/bootstrap-components"; import {Icon} from "../../lib/bootstrap-components";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@withTranslation() @withTranslation()
@ -23,7 +23,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
this.fieldTypes = getFieldTypes(props.t); this.fieldTypes = getFieldTypes(props.t);
} }
@ -55,7 +55,7 @@ export default class List extends Component {
link: `/lists/${this.props.list.id}/fields/${data[0]}/edit` link: `/lists/${this.props.list.id}/fields/${data[0]}/edit`
}); });
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]); tableAddDeleteButton(actions, this, null, `rest/fields/${this.props.list.id}/${data[0]}`, data[1], t('deletingField'), t('fieldDeleted'));
} }
return actions; return actions;
@ -65,7 +65,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/fields/${this.props.list.id}`, t('deletingField'), t('fieldDeleted'))} {tableRestActionDialogRender(this)}
{this.props.list.permissions.includes('manageFields') && {this.props.list.permissions.includes('manageFields') &&
<Toolbar> <Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/fields/create`} className="btn-primary" icon="plus" label={t('createField')}/> <NavButton linkTo={`/lists/${this.props.list.id}/fields/create`} className="btn-primary" icon="plus" label={t('createField')}/>

View file

@ -9,9 +9,9 @@ import axios from '../../lib/axios';
import {Icon} from "../../lib/bootstrap-components"; import {Icon} from "../../lib/bootstrap-components";
import {checkPermissions} from "../../lib/permissions"; import {checkPermissions} from "../../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@withTranslation() @withTranslation()
@ -23,7 +23,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -70,7 +70,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/forms/${data[0]}`, data[1], t('deletingForm'), t('formDeleted'));
return actions; return actions;
} }
@ -79,7 +79,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/forms`, t('deletingForm'), t('formDeleted'))} {tableRestActionDialogRender(this)}
{this.state.createPermitted && {this.state.createPermitted &&
<Toolbar> <Toolbar>
<NavButton linkTo="/lists/forms/create" className="btn-primary" icon="plus" label={t('createCustomForm')}/> <NavButton linkTo="/lists/forms/create" className="btn-primary" icon="plus" label={t('createCustomForm')}/>

View file

@ -18,9 +18,9 @@ import mailtrainConfig from 'mailtrainConfig';
import moment from "moment"; import moment from "moment";
import {inProgress} from '../../../../shared/imports'; import {inProgress} from '../../../../shared/imports';
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@withTranslation() @withTranslation()
@ -32,7 +32,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
const {importSourceLabels, importStatusLabels} = getImportLabels(props.t); const {importSourceLabels, importStatusLabels} = getImportLabels(props.t);
this.importSourceLabels = importSourceLabels; this.importSourceLabels = importSourceLabels;
@ -79,7 +79,7 @@ export default class List extends Component {
}); });
if (this.props.list.permissions.includes('manageImports')) { if (this.props.list.permissions.includes('manageImports')) {
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]); tableAddDeleteButton(actions, this, null, `rest/imports/${this.props.list.id}/${data[0]}`, data[1], t('deletingImport'), t('importDeleted'));
} }
return { refreshTimeout, actions }; return { refreshTimeout, actions };
@ -89,7 +89,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/imports/${this.props.list.id}`, t('deletingImport'), t('importDeleted'))} {tableRestActionDialogRender(this)}
{mailtrainConfig.globalPermissions.setupAutomation && this.props.list.permissions.includes('manageImports') && {mailtrainConfig.globalPermissions.setupAutomation && this.props.list.permissions.includes('manageImports') &&
<Toolbar> <Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/imports/create`} className="btn-primary" icon="plus" label={t('createImport')}/> <NavButton linkTo={`/lists/${this.props.list.id}/imports/create`} className="btn-primary" icon="plus" label={t('createImport')}/>

View file

@ -8,9 +8,9 @@ import { withErrorHandling } from '../../lib/error-handling';
import { Table } from '../../lib/table'; import { Table } from '../../lib/table';
import {Icon} from "../../lib/bootstrap-components"; import {Icon} from "../../lib/bootstrap-components";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@withTranslation() @withTranslation()
@ -22,7 +22,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
static propTypes = { static propTypes = {
@ -47,7 +47,7 @@ export default class List extends Component {
link: `/lists/${this.props.list.id}/segments/${data[0]}/edit` link: `/lists/${this.props.list.id}/segments/${data[0]}/edit`
}); });
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]); tableAddDeleteButton(actions, this, null, `rest/segments/${this.props.list.id}/${data[0]}`, data[1], t('deletingSegment'), t('segmentDeleted'));
} }
return actions; return actions;
@ -57,7 +57,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/segments/${this.props.list.id}`, t('deletingSegment'), t('segmentDeleted'))} {tableRestActionDialogRender(this)}
{this.props.list.permissions.includes('manageSegments') && {this.props.list.permissions.includes('manageSegments') &&
<Toolbar> <Toolbar>
<NavButton linkTo={`/lists/${this.props.list.id}/segments/create`} className="btn-primary" icon="plus" label={t('createSegment')}/> <NavButton linkTo={`/lists/${this.props.list.id}/segments/create`} className="btn-primary" icon="plus" label={t('createSegment')}/>

View file

@ -129,7 +129,7 @@ export function getRuleHelpers(t, fields) {
}, },
eqTodayPlusDays: { eqTodayPlusDays: {
dropdownLabel: t('onXthDayBeforeafterCurrentDate'), dropdownLabel: t('onXthDayBeforeafterCurrentDate'),
treeLabel: rule => getRelativeDateTreeLabel(rule, 'is', [tMark('dateInColumnColNameIsTheCurrentDate'), tMark('dateInColumnColNameIsValuethDayAfterThe'), tMark('dateInColumnColNameIsValuethDayBeforeThe')]), treeLabel: rule => getRelativeDateTreeLabel(rule, [tMark('dateInColumnColNameIsTheCurrentDate'), tMark('dateInColumnColNameIsValuethDayAfterThe'), tMark('dateInColumnColNameIsValuethDayBeforeThe')]),
}, },
ltTodayPlusDays: { ltTodayPlusDays: {
dropdownLabel: t('beforeXthDayBeforeafterCurrentDate'), dropdownLabel: t('beforeXthDayBeforeafterCurrentDate'),

View file

@ -13,15 +13,16 @@ import {
withForm withForm
} from '../../lib/form'; } from '../../lib/form';
import {Icon, Button} from "../../lib/bootstrap-components"; import {Icon, Button} from "../../lib/bootstrap-components";
import axios, {HTTPMethod} from '../../lib/axios'; import {HTTPMethod} from '../../lib/axios';
import {getFieldTypes, getSubscriptionStatusLabels} from './helpers'; import {getFieldTypes, getSubscriptionStatusLabels} from './helpers';
import {getUrl, getPublicUrl} from "../../lib/urls"; import {getUrl, getPublicUrl} from "../../lib/urls";
import { import {
DeleteModalDialog, DeleteModalDialog,
RestActionModalDialog, RestActionModalDialog,
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender,
tableAddRestActionButton
} from "../../lib/modals"; } from "../../lib/modals";
import listStyles from "../styles.scss"; import listStyles from "../styles.scss";
import styles from '../../lib/styles.scss'; import styles from '../../lib/styles.scss';
@ -38,7 +39,7 @@ export default class List extends Component {
const t = props.t; const t = props.t;
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
this.subscriptionStatusLabels = getSubscriptionStatusLabels(t); this.subscriptionStatusLabels = getSubscriptionStatusLabels(t);
this.fieldTypes = getFieldTypes(t); this.fieldTypes = getFieldTypes(t);
@ -72,18 +73,6 @@ export default class List extends Component {
this.updateSegmentSelection(nextProps); this.updateSegmentSelection(nextProps);
} }
@withAsyncErrorHandler
async unsubscribeSubscription(id) {
await axios.post(getUrl(`rest/subscriptions-unsubscribe/${this.props.list.id}/${id}`));
this.table.refresh();
}
@withAsyncErrorHandler
async blacklistSubscription(email) {
await axios.post(getUrl('rest/blacklist'), { email });
this.table.refresh();
}
render() { render() {
const t = this.props.t; const t = this.props.t;
const list = this.props.list; const list = this.props.list;
@ -126,20 +115,32 @@ export default class List extends Component {
}); });
if (email && status === SubscriptionStatus.SUBSCRIBED) { if (email && status === SubscriptionStatus.SUBSCRIBED) {
actions.push({ tableAddRestActionButton(
label: <Icon icon="off" title={t('unsubscribe')}/>, actions, this,
action: () => this.unsubscribeSubscription(id) { method: HTTPMethod.POST, url: `rest/subscriptions-unsubscribe/${this.props.list.id}/${id}`},
}); { icon: 'off', label: t('unsubscribe') },
t('Confirm Unsubscription'),
t('Are you sure you want to unsubscribe {{email}}?', {email}),
t('Unsubscribing {{email}}', {email}),
t('{{email}} unsubscribed', {email}),
null
);
} }
if (email && !data[5]) { if (email && !data[5]) {
actions.push({ tableAddRestActionButton(
label: <Icon icon="ban-circle" title={t('blacklist')}/>, actions, this,
action: () => this.blacklistSubscription(email) { method: HTTPMethod.POST, url: `rest/blacklist`, data: {email} },
}); { icon: 'ban-circle', label: t('blacklist') },
t('Confirm Email Blacklisting'),
t('Are you sure you want to blacklist {{email}}?', {email}),
t('Blacklisting {{email}}', {email}),
t('{{email}} blacklisted', {email}),
null
);
} }
tableDeleteDialogAddDeleteButton(actions, this, null, id, email); tableAddDeleteButton(actions, this, null, `rest/subscriptions/${this.props.list.id}/${id}`, email, t('deletingSubscription'), t('subscriptionDeleted'));
return actions; return actions;
} }
@ -161,7 +162,7 @@ export default class List extends Component {
// FIXME - presents segments in a data table as in campaign edit // FIXME - presents segments in a data table as in campaign edit
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/subscriptions/${this.props.list.id}`, t('deletingSubscription'), t('subscriptionDeleted'))} {tableRestActionDialogRender(this)}
<Toolbar> <Toolbar>
<a href={getPublicUrl(`subscription/${this.props.list.cid}`)}><Button label={t('subscriptionForm')} className="btn-default"/></a> <a href={getPublicUrl(`subscription/${this.props.list.cid}`)}><Button label={t('subscriptionForm')} className="btn-default"/></a>
<a href={getUrl(`subscriptions/export/${this.props.list.id}/`+ (this.props.segmentId || 0))}><Button label={t('exportAsCsv')} className="btn-primary"/></a> <a href={getUrl(`subscriptions/export/${this.props.list.id}/`+ (this.props.segmentId || 0))}><Button label={t('exportAsCsv')} className="btn-primary"/></a>

View file

@ -9,9 +9,9 @@ import axios from '../lib/axios';
import {Icon} from "../lib/bootstrap-components"; import {Icon} from "../lib/bootstrap-components";
import {checkPermissions} from "../lib/permissions"; import {checkPermissions} from "../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
import {getGlobalNamespaceId} from "../../../shared/namespaces"; import {getGlobalNamespaceId} from "../../../shared/namespaces";
@ -24,7 +24,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -67,7 +67,7 @@ export default class List extends Component {
} }
if (Number.parseInt(node.key) !== getGlobalNamespaceId()) { if (Number.parseInt(node.key) !== getGlobalNamespaceId()) {
tableDeleteDialogAddDeleteButton(actions, this, node.data.permissions, node.key, node.data.unsanitizedTitle); tableAddDeleteButton(actions, this, node.data.permissions, `rest/namespaces/${node.key}`, node.data.unsanitizedTitle, t('deletingNamespace'), t('namespaceDeleted'));
} }
return actions; return actions;
@ -75,7 +75,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/namespaces`, t('deletingNamespace'), t('namespaceDeleted'))} {tableRestActionDialogRender(this)}
{this.state.createPermitted && {this.state.createPermitted &&
<Toolbar> <Toolbar>
<NavButton linkTo="/namespaces/create" className="btn-primary" icon="plus" label={t('createNamespace')}/> <NavButton linkTo="/namespaces/create" className="btn-primary" icon="plus" label={t('createNamespace')}/>

View file

@ -12,9 +12,9 @@ import {Icon} from "../lib/bootstrap-components";
import {checkPermissions} from "../lib/permissions"; import {checkPermissions} from "../lib/permissions";
import {getUrl} from "../lib/urls"; import {getUrl} from "../lib/urls";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@withTranslation() @withTranslation()
@ -26,7 +26,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -165,7 +165,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/reports/${data[0]}`, data[1], t('deletingReport'), t('reportDeleted'));
return { refreshTimeout, actions }; return { refreshTimeout, actions };
} }
@ -175,7 +175,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/reports`, t('deletingReport'), t('reportDeleted'))} {tableRestActionDialogRender(this)}
<Toolbar> <Toolbar>
{this.state.createPermitted && {this.state.createPermitted &&
<NavButton linkTo="/reports/create" className="btn-primary" icon="plus" label={t('createReport')}/> <NavButton linkTo="/reports/create" className="btn-primary" icon="plus" label={t('createReport')}/>

View file

@ -11,9 +11,9 @@ import moment from 'moment';
import mailtrainConfig from 'mailtrainConfig'; import mailtrainConfig from 'mailtrainConfig';
import {checkPermissions} from "../../lib/permissions"; import {checkPermissions} from "../../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@withTranslation() @withTranslation()
@ -25,7 +25,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -74,7 +74,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/reports/templates/${data[0]}`, data[1], t('deletingReportTemplate'), t('reportTemplateDeleted'));
return actions; return actions;
} }
@ -83,7 +83,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/reports/templates`, t('deletingReportTemplate'), t('reportTemplateDeleted'))} {tableRestActionDialogRender(this)}
{this.state.createPermitted && {this.state.createPermitted &&
<Toolbar> <Toolbar>
<DropdownMenu className="btn-primary" label={t('createReportTemplate')}> <DropdownMenu className="btn-primary" label={t('createReportTemplate')}>

View file

@ -20,9 +20,9 @@ import moment from 'moment';
import {getMailerTypes} from './helpers'; import {getMailerTypes} from './helpers';
import {checkPermissions} from "../lib/permissions"; import {checkPermissions} from "../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@ -37,7 +37,7 @@ export default class List extends Component {
this.mailerTypes = getMailerTypes(props.t); this.mailerTypes = getMailerTypes(props.t);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -88,7 +88,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/send-configurations/${data[0]}`, data[1], t('deletingSendConfiguration'), t('sendConfigurationDeleted'));
return actions; return actions;
} }
@ -97,7 +97,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/send-configurations`, t('deletingSendConfiguration'), t('sendConfigurationDeleted'))} {tableRestActionDialogRender(this)}
{this.state.createPermitted && {this.state.createPermitted &&
<Toolbar> <Toolbar>
<NavButton linkTo="/send-configurations/create" className="btn-primary" icon="plus" label={t('createSendConfiguration')}/> <NavButton linkTo="/send-configurations/create" className="btn-primary" icon="plus" label={t('createSendConfiguration')}/>

View file

@ -19,9 +19,9 @@ import moment from 'moment';
import {getTemplateTypes} from './helpers'; import {getTemplateTypes} from './helpers';
import {checkPermissions} from "../lib/permissions"; import {checkPermissions} from "../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@withTranslation() @withTranslation()
@ -35,7 +35,7 @@ export default class List extends Component {
this.templateTypes = getTemplateTypes(props.t); this.templateTypes = getTemplateTypes(props.t);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -101,7 +101,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/templates/${data[0]}`, data[1], t('deletingTemplate'), t('templateDeleted'));
return actions; return actions;
} }
@ -110,7 +110,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/templates`, t('deletingTemplate'), t('templateDeleted'))} {tableRestActionDialogRender(this)}
<Toolbar> <Toolbar>
{this.state.createPermitted && {this.state.createPermitted &&
<NavButton linkTo="/templates/create" className="btn-primary" icon="plus" label={t('createTemplate')}/> <NavButton linkTo="/templates/create" className="btn-primary" icon="plus" label={t('createTemplate')}/>

View file

@ -11,9 +11,9 @@ import moment from 'moment';
import { getTemplateTypes } from './helpers'; import { getTemplateTypes } from './helpers';
import {checkPermissions} from "../../lib/permissions"; import {checkPermissions} from "../../lib/permissions";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../../lib/modals"; } from "../../lib/modals";
@ -28,7 +28,7 @@ export default class List extends Component {
this.templateTypes = getTemplateTypes(props.t); this.templateTypes = getTemplateTypes(props.t);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
@withAsyncErrorHandler @withAsyncErrorHandler
@ -92,7 +92,7 @@ export default class List extends Component {
}); });
} }
tableDeleteDialogAddDeleteButton(actions, this, perms, data[0], data[1]); tableAddDeleteButton(actions, this, perms, `rest/mosaico-templates/${data[0]}`, data[1], t('deletingMosaicoTemplate'), t('mosaicoTemplateDeleted'));
return actions; return actions;
} }
@ -101,7 +101,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/mosaico-templates`, t('deletingMosaicoTemplate'), t('mosaicoTemplateDeleted'))} {tableRestActionDialogRender(this)}
{this.state.createPermitted && {this.state.createPermitted &&
<Toolbar> <Toolbar>
<DropdownMenu className="btn-primary" label={t('createMosaicoTemplate')}> <DropdownMenu className="btn-primary" label={t('createMosaicoTemplate')}>

View file

@ -7,9 +7,9 @@ import {Table} from "../lib/table";
import mailtrainConfig from "mailtrainConfig"; import mailtrainConfig from "mailtrainConfig";
import {Icon} from "../lib/bootstrap-components"; import {Icon} from "../lib/bootstrap-components";
import { import {
tableDeleteDialogAddDeleteButton, tableAddDeleteButton,
tableDeleteDialogInit, tableRestActionDialogInit,
tableDeleteDialogRender tableRestActionDialogRender
} from "../lib/modals"; } from "../lib/modals";
@withTranslation() @withTranslation()
@ -20,7 +20,7 @@ export default class List extends Component {
super(props); super(props);
this.state = {}; this.state = {};
tableDeleteDialogInit(this); tableRestActionDialogInit(this);
} }
render() { render() {
@ -54,7 +54,7 @@ export default class List extends Component {
link: `/users/${data[0]}/shares` link: `/users/${data[0]}/shares`
}); });
tableDeleteDialogAddDeleteButton(actions, this, null, data[0], data[1]); tableAddDeleteButton(actions, this, null, `rest/users/${data[0]}`, data[1], t('deletingUser'), t('userDeleted'));
return actions; return actions;
} }
@ -62,7 +62,7 @@ export default class List extends Component {
return ( return (
<div> <div>
{tableDeleteDialogRender(this, `rest/users`, t('deletingUser'), t('userDeleted'))} {tableRestActionDialogRender(this)}
<Toolbar> <Toolbar>
<NavButton linkTo="/users/create" className="btn-primary" icon="plus" label={t('createUser')}/> <NavButton linkTo="/users/create" className="btn-primary" icon="plus" label={t('createUser')}/>
</Toolbar> </Toolbar>

View file

@ -310,7 +310,7 @@
"mosaicoTemplate_plural": "Mosaico templates", "mosaicoTemplate_plural": "Mosaico templates",
"cannoteDeleteNameDueToTheFollowing": "Cannote delete \"{{name}}\" due to the following dependencies:", "cannoteDeleteNameDueToTheFollowing": "Cannote delete \"{{name}}\" due to the following dependencies:",
"andMore": "... and more", "andMore": "... and more",
"confirmDeletion": "Confirm deletion", "confirmDeletion": "Confirm Deletion",
"areYouSureYouWantToDeleteName?": "Are you sure you want to delete \"{{name}}\"?", "areYouSureYouWantToDeleteName?": "Are you sure you want to delete \"{{name}}\"?",
"namespacemustBeSelected": "namespace.mustBeSelected", "namespacemustBeSelected": "namespace.mustBeSelected",
"mjml": "MJML", "mjml": "MJML",
@ -559,24 +559,24 @@
"dateInColumnColNameIsAfterOrOnValue": "Date in column \"{{colName}}\" is after or on {{value}}", "dateInColumnColNameIsAfterOrOnValue": "Date in column \"{{colName}}\" is after or on {{value}}",
"onXthDayBeforeafterCurrentDate": "On x-th day before/after current date", "onXthDayBeforeafterCurrentDate": "On x-th day before/after current date",
"dateInColumnColNameIsTheCurrentDate": "Date in column \"{{colName}}\" is the current date", "dateInColumnColNameIsTheCurrentDate": "Date in column \"{{colName}}\" is the current date",
"dateInColumnColNameIsValuethDayAfterThe": "Date in column \"{{colName}}\" is {{value}}-th day after the current date", "dateInColumnColNameIsValuethDayAfterThe": "Date in column \"{{colName}}\" is the {{value}}-th day after the current date",
"dateInColumnColNameIsValuethDayBeforeThe": "Date in column \"{{colName}}\" is {{value}}-th day before the current date", "dateInColumnColNameIsValuethDayBeforeThe": "Date in column \"{{colName}}\" is the {{value}}-th day before the current date",
"beforeXthDayBeforeafterCurrentDate": "Before x-th day before/after current date", "beforeXthDayBeforeafterCurrentDate": "Before x-th day before/after current date",
"dateInColumnColNameIsBeforeTheCurrent": "Date in column \"{{colName}}\" is before the current date", "dateInColumnColNameIsBeforeTheCurrent": "Date in column \"{{colName}}\" is before the current date",
"dateInColumnColNameIsBeforeValuethDay": "Date in column \"{{colName}}\" is before {{value}}-th day after the current date", "dateInColumnColNameIsBeforeValuethDay": "Date in column \"{{colName}}\" is before the {{value}}-th day after the current date",
"dateInColumnColNameIsBeforeValuethDay-1": "Date in column \"{{colName}}\" is before {{value}}-th day before the current date", "dateInColumnColNameIsBeforeValuethDay-1": "Date in column \"{{colName}}\" is before the {{value}}-th day before the current date",
"beforeOrOnXthDayBeforeafterCurrentDate": "Before or on x-th day before/after current date", "beforeOrOnXthDayBeforeafterCurrentDate": "Before or on x-th day before/after current date",
"dateInColumnColNameIsBeforeOrOnThe": "Date in column \"{{colName}}\" is before or on the current date", "dateInColumnColNameIsBeforeOrOnThe": "Date in column \"{{colName}}\" is before or on the current date",
"dateInColumnColNameIsBeforeOrOnValueth": "Date in column \"{{colName}}\" is before or on {{value}}-th day after the current date", "dateInColumnColNameIsBeforeOrOnValueth": "Date in column \"{{colName}}\" is before or on the {{value}}-th day after the current date",
"dateInColumnColNameIsBeforeOrOnValueth-1": "Date in column \"{{colName}}\" is before or on {{value}}-th day before the current date", "dateInColumnColNameIsBeforeOrOnValueth-1": "Date in column \"{{colName}}\" is before or on the {{value}}-th day before the current date",
"afterXthDayBeforeafterCurrentDate": "After x-th day before/after current date", "afterXthDayBeforeafterCurrentDate": "After x-th day before/after current date",
"dateInColumnColNameIsAfterTheCurrentDate": "Date in column \"{{colName}}\" is after the current date", "dateInColumnColNameIsAfterTheCurrentDate": "Date in column \"{{colName}}\" is after the current date",
"dateInColumnColNameIsAfterValuethDay": "Date in column \"{{colName}}\" is after {{value}}-th day after the current date", "dateInColumnColNameIsAfterValuethDay": "Date in column \"{{colName}}\" is after the {{value}}-th day after the current date",
"dateInColumnColNameIsAfterValuethDay-1": "Date in column \"{{colName}}\" is after {{value}}-th day before the current date", "dateInColumnColNameIsAfterValuethDay-1": "Date in column \"{{colName}}\" is after the {{value}}-th day before the current date",
"afterOrOnXthDayBeforeafterCurrentDate": "After or on x-th day before/after current date", "afterOrOnXthDayBeforeafterCurrentDate": "After or on x-th day before/after current date",
"dateInColumnColNameIsAfterOrOnTheCurrent": "Date in column \"{{colName}}\" is after or on the current date", "dateInColumnColNameIsAfterOrOnTheCurrent": "Date in column \"{{colName}}\" is after or on the current date",
"dateInColumnColNameIsAfterOrOnValuethDay": "Date in column \"{{colName}}\" is after or on {{value}}-th day after the current date", "dateInColumnColNameIsAfterOrOnValuethDay": "Date in column \"{{colName}}\" is after or on the {{value}}-th day after the current date",
"dateInColumnColNameIsAfterOrOnValuethDay-1": "Date in column \"{{colName}}\" is after or on {{value}}-th day before the current date", "dateInColumnColNameIsAfterOrOnValuethDay-1": "Date in column \"{{colName}}\" is after or on the {{value}}-th day before the current date",
"isSelected": "Is selected", "isSelected": "Is selected",
"valueInColumnColNameIsSelected": "Value in column \"{{colName}}\" is selected", "valueInColumnColNameIsSelected": "Value in column \"{{colName}}\" is selected",
"isNotSelected": "Is not selected", "isNotSelected": "Is not selected",

View file

@ -4,6 +4,7 @@ const knex = require('../lib/knex');
const dtHelpers = require('../lib/dt-helpers'); const dtHelpers = require('../lib/dt-helpers');
const shares = require('./shares'); const shares = require('./shares');
const tools = require('../lib/tools'); const tools = require('../lib/tools');
const { enforce } = require('../lib/helpers');
async function listDTAjax(context, params) { async function listDTAjax(context, params) {
shares.enforceGlobalPermission(context, 'manageBlacklist'); shares.enforceGlobalPermission(context, 'manageBlacklist');

View file

@ -177,10 +177,6 @@ async function remove(context, id) {
await knex.transaction(async tx => { await knex.transaction(async tx => {
await shares.enforceEntityPermissionTx(tx, context, 'list', id, 'delete'); await shares.enforceEntityPermissionTx(tx, context, 'list', id, 'delete');
await fields.removeAllByListIdTx(tx, context, id);
await segments.removeAllByListIdTx(tx, context, id);
await imports.removeAllByListIdTx(tx, context, id);
await dependencyHelpers.ensureNoDependencies(tx, context, id, [ await dependencyHelpers.ensureNoDependencies(tx, context, id, [
{ {
entityTypeId: 'campaign', entityTypeId: 'campaign',
@ -191,6 +187,10 @@ async function remove(context, id) {
} }
]); ]);
await fields.removeAllByListIdTx(tx, context, id);
await segments.removeAllByListIdTx(tx, context, id);
await imports.removeAllByListIdTx(tx, context, id);
await tx('lists').where('id', id).del(); await tx('lists').where('id', id).del();
await knex.schema.dropTableIfExists('subscription__' + id); await knex.schema.dropTableIfExists('subscription__' + id);
}); });

View file

@ -85,8 +85,6 @@ async function updateWithConsistencyCheck(context, entity) {
async function remove(context, id) { async function remove(context, id) {
await knex.transaction(async tx => { await knex.transaction(async tx => {
const deps = [];
await shares.enforceEntityPermissionTx(tx, context, 'mosaicoTemplate', id, 'delete'); await shares.enforceEntityPermissionTx(tx, context, 'mosaicoTemplate', id, 'delete');
await dependencyHelpers.ensureNoDependencies(tx, context, id, [ await dependencyHelpers.ensureNoDependencies(tx, context, id, [